Como você faz isso? Dada uma matriz de bytes:
byte[] foo = new byte[4096];
Como eu obteria os primeiros x bytes da matriz como uma matriz separada? (Especificamente, eu preciso dele como um IEnumerable<byte>
)
Isto é para trabalhar com Socket
s. Eu acho que a maneira mais fácil seria fatiar o array, semelhante à sintaxe Perls:
@bar = @foo[0..40];
O que retornaria os primeiros 41 elementos na @bar
matriz. Existe alguma coisa em C # que estou perdendo ou há outra coisa que devo fazer?
O LINQ é uma opção para mim (.NET 3.5), se isso ajudar alguma.
Respostas:
As matrizes são enumeráveis, então você
foo
já é uma pessoaIEnumerable<byte>
. Simplesmente use métodos de sequência LINQ comoTake()
obter o que você deseja (não se esqueça de incluir oLinq
espaço para nomeusing System.Linq;
):Se você realmente precisar de uma matriz de qualquer
IEnumerable<byte>
valor, poderá usar oToArray()
método para isso. Esse não parece ser o caso aqui.fonte
[2,3] => [1,1], [1,2], [1,3], [2,1], [2,2], [2,3]
. Matrizes irregulares também são enumeráveis, mas em vez de retornar um valor quando enumeradas, elas retornam sua matriz interna. Assim:type[][] jaggedArray; foreach (type[] innerArray in jaggedArray) { }
IEnumerable<T>
", então minha declaração teria sido mais clara. Veja também: stackoverflow.com/questions/721882/…Você poderia usar
ArraySegment<T>
. É muito leve, pois não copia a matriz:fonte
Você pode usar o
CopyTo()
método matrizes .Ou com o LINQ você pode usar
Skip()
eTake()
...fonte
Skip()
. SóTake()
não vai te dar uma fatia arbitrária. Além disso, eu estava procurando uma solução LINQ de qualquer maneira (fatia IEnumerable, mas sabia que os resultados sobre a matriz seriam mais fáceis de encontrar).//
fonte
A partir do C # 8.0 / .Net Core 3.0
O corte de matriz será suportado, junto com os novos tipos
Index
eRange
será adicionado.Documentos do Range Struct documentos do
Struct
Exemplo de código acima, retirado do blog C # 8.0 .
observe que o
^
prefixo indica a contagem a partir do final da matriz. Como mostrado no exemplo de documentosRange
eIndex
também trabalha fora de matrizes de fatiamento, por exemplo, com loopsPercorrerá as entradas 1 a 4
Observe que, no momento em que escrevemos esta resposta, o C # 8.0 ainda não havia sido lançado oficialmente, oC # 8.xe o .NET Core 3.x já estavam disponíveis no Visual Studio 2019 e posteriores.
fonte
No C # 7.2 , você pode usar
Span<T>
. O benefício do novoSystem.Memory
sistema é que ele não precisa copiar dados.O método que você precisa é
Slice
:Muitos métodos agora suportam
Span
eIReadOnlySpan
, portanto, será muito simples usar esse novo tipo.Observe que, no momento da escrita, o
Span<T>
tipo ainda não está definido na versão mais recente do .NET (4.7.1). Para usá-lo, é necessário instalar o pacote System.Memory do NuGet.fonte
Span<T>
tipo ainda não está definido na versão mais recente do .Net (4.7.1). Para usá-lo, você precisa instalar oSystem.Memory
NuGet (e lembre-se de marcar "incluir pré-lançamento" ao procurá-lo no NuGet)Outra possibilidade que eu não vi mencionada aqui: Buffer.BlockCopy () é um pouco mais rápida que Array.Copy () e tem o benefício adicional de poder converter on-the-fly a partir de uma matriz de primitivas (por exemplo, []) para uma matriz de bytes, o que pode ser útil quando você possui matrizes numéricas que precisam transmitir por soquetes.
fonte
Buffer.BlockCopy
produziu resultados diferentes do queArray.Copy()
mesmo que aceitem os mesmos parâmetros - havia muitos elementos vazios. Por quê?Array.Copy(array1, 0, array2, 0, 10)
, masBuffer.BlockCopy(array1, 0, array2, 0, 10 * sizeof(int))
.Se você quiser
IEnumerable<byte>
, então apenasfonte
Aqui está um método de extensão simples que retorna uma fatia como uma nova matriz:
Então você pode usá-lo como:
fonte
Se você não deseja adicionar LINQ ou outras extensões, basta:
fonte
Error CS0246: The type or namespace name 'List<>' could not be found (are you missing a using directive or an assembly reference?)
A documentação da Microsoft é inútil com centenas de entradas "Lista" indexadas. Qual é o caminho certo aqui?System.Collections.Generic.List
Você pode usar um wrapper em torno da matriz original (que é IList), como neste pedaço de código (não testado).
}
fonte
Array.Copy
, embora isso possa ter muitas vantagens, como o SubList literalmente sendo uma região na Lista pai, em vez de uma cópia das entradas na Lista.fonte
Para matrizes de bytes, o System.Buffer.BlockCopy oferece o melhor desempenho.
fonte
Você pode usar o método Take extension
fonte
Esta pode ser uma solução que:
Em seguida, o resultado é um IEnumerable <IEnumerable <byte >> com um primeiro IEnumerable <byte> contém os primeiros 40 bytes de foo e um segundo IEnumerable <byte> mantém o restante.
Eu escrevi uma classe de wrapper, toda a iteração é preguiçosa, espero que ajude:
fonte
Eu não acho que o C # suporta a semântica do intervalo. Você pode escrever um método de extensão, como:
Mas, como outros já disseram, se você não precisa definir um índice inicial,
Take
é tudo o que precisa.fonte
Aqui está uma função de extensão que usa um genérico e se comporta como a função PHP array_slice . Deslocamento negativo e comprimento são permitidos.
fonte
start
não estiver entre 0 earr.Length
, provavelmente deve gerar uma exceção fora dos limites. Além disso,end >= start >= 0
para que você não precise verificarend < 0
, não é possível que isso aconteça. Você provavelmente poderia fazê-lo ainda mais sucintamente verificando issolength >= 0
e depois emlen = Math.min(length, arr.Length - start)
vez de se enganarend
.fonte