¿Cómo lo haces? Dado un conjunto de bytes:
byte[] foo = new byte[4096];
¿Cómo obtendría los primeros x bytes de la matriz como una matriz separada? (Específicamente, lo necesito como un IEnumerable<byte>
)
Esto es para trabajar con Socket
s. Me imagino que la forma más fácil sería el corte de matriz, similar a la sintaxis de Perls:
@bar = @foo[0..40];
Lo que devolvería los primeros 41 elementos en la @bar
matriz. ¿Hay algo en C # que solo me estoy perdiendo, o hay alguna otra cosa que debería estar haciendo?
LINQ es una opción para mí (.NET 3.5), si eso ayuda.
Respuestas:
Las matrices son enumerables, por lo que su
foo
ya es unIEnumerable<byte>
sí mismo. Simplemente use métodos de secuencia LINQ comoTake()
obtener lo que desea de él (no olvide incluir elLinq
espacio de nombres conusing System.Linq;
):Si realmente necesita una matriz de cualquier
IEnumerable<byte>
valor, puede usar elToArray()
método para eso. Ese no parece ser el caso aquí.fuente
[2,3] => [1,1], [1,2], [1,3], [2,1], [2,2], [2,3]
. Las matrices irregulares también son enumerables, pero en lugar de devolver un valor cuando se enumeran, devuelven su matriz interna. Así:type[][] jaggedArray; foreach (type[] innerArray in jaggedArray) { }
IEnumerable<T>
", entonces mi declaración habría sido más clara. Vea también esto: stackoverflow.com/questions/721882/…Podrías usar
ArraySegment<T>
. Es muy liviano ya que no copia la matriz:fuente
Podrías usar el
CopyTo()
método de matrices .O con LINQ puede usar
Skip()
yTake()
...fuente
Skip()
. SimplementeTake()
no te dará una porción arbitraria. Además, estaba buscando una solución LINQ de todos modos (rebanada IEnumerable, pero sabía que los resultados sobre la matriz serían más fáciles de encontrar).//
fuente
A partir de C # 8.0 / .Net Core 3.0
Se admitirá el corte de matriz, junto con los nuevos tipos
Index
y laRange
adición.Range Struct docs
Index Struct docs
Ejemplo de código anterior tomado del blog C # 8.0 .
tenga en cuenta que el
^
prefijo indica contar desde el final de la matriz. Como se muestra en el ejemplo de documentaciónRange
yIndex
también funcionan fuera de las matrices de corte, por ejemplo con buclesRecorrerá las entradas 1 a 4
tenga en cuenta que al momento de escribir esta respuesta, C # 8.0 aún no se ha lanzado oficialmenteC # 8.xy .Net Core 3.x ahora están disponibles en Visual Studio 2019 y en adelante
fuente
En C # 7.2 , puede usar
Span<T>
. El beneficio del nuevoSystem.Memory
sistema es que no necesita copiar datos.El método que necesitas es
Slice
:Muchos métodos ahora son compatibles
Span
yIReadOnlySpan
, por lo tanto, será muy sencillo utilizar este nuevo tipo.Tenga en cuenta que al momento de escribir este
Span<T>
tipo aún no está definido en la versión más reciente de .NET (4.7.1), por lo que para usarlo debe instalar el paquete System.Memory de NuGet.fuente
Span<T>
tipo aún no está definido en la versión más reciente de .Net (4.7.1), por lo que para usarlo debe instalarSystem.Memory
NuGet (y recuerde marcar "incluir prelanzamiento" cuando lo busque en NuGet)Otra posibilidad que no he visto mencionada aquí: Buffer.BlockCopy () es un poco más rápido que Array.Copy (), y tiene el beneficio adicional de poder convertir sobre la marcha de una serie de primitivas (digamos, short []) a una matriz de bytes, que puede ser útil cuando tienes matrices numéricas que necesitas transmitir a través de Sockets.
fuente
Buffer.BlockCopy
produjo resultados diferentes aArray.Copy()
pesar de que aceptan los mismos parámetros: había muchos elementos vacíos. ¿Por qué?Array.Copy(array1, 0, array2, 0, 10)
, peroBuffer.BlockCopy(array1, 0, array2, 0, 10 * sizeof(int))
.Si quieres
IEnumerable<byte>
, entonces solofuente
Aquí hay un método de extensión simple que devuelve un segmento como una nueva matriz:
Entonces puedes usarlo como:
fuente
Si no desea agregar LINQ u otras extensiones, simplemente haga lo siguiente:
fuente
Error CS0246: The type or namespace name 'List<>' could not be found (are you missing a using directive or an assembly reference?)
La documentación de Microsoft es inútil con cientos de entradas de "Lista" indexadas. ¿Cuál es el correcto aquí?System.Collections.Generic.List
Podría usar un contenedor alrededor de la matriz original (que es IList), como en este fragmento de código (no probado).
}
fuente
Array.Copy
, a pesar de que esto puede tener muchas ventajas, como que la Sublista es literalmente una región dentro de la Lista principal, en lugar de una copia de las entradas en la Lista.fuente
Para las matrices de bytes, System.Buffer.BlockCopy le dará el mejor rendimiento.
fuente
Puede usar el método de extensión Take
fuente
Esta puede ser una solución que:
Entonces el resultado es un IEnumerable <IEnumerable <byte >> con un primer IEnumerable <byte> contiene los primeros 40 bytes de foo , y un segundo IEnumerable <byte> contiene el resto.
Escribí una clase de contenedor, toda la iteración es perezosa, espero que pueda ayudar:
fuente
No creo que C # sea compatible con la semántica de Range. Sin embargo, podría escribir un método de extensión, como:
Pero, como han dicho otros, si no necesita establecer un índice de inicio, entonces
Take
es todo lo que necesita.fuente
Aquí hay una función de extensión que usa un genérico y se comporta como la función PHP array_slice . El desplazamiento negativo y la longitud están permitidos.
fuente
start
no está entre 0 yarr.Length
, probablemente debería arrojar una excepción fuera de límites. Además,end >= start >= 0
por lo que no necesita verificarend < 0
, no es posible que suceda. Probablemente podría hacerlo aún más sucintamente comprobando esolength >= 0
y luego enlen = Math.min(length, arr.Length - start)
lugar de jugar con élend
.fuente