2008-08-21 23 views
26

Tengo una matriz de bytes en la memoria, leo desde un archivo. Me gustaría dividir la matriz de bytes en un cierto punto (índice) sin tener que crear una nueva matriz de bytes y copiar cada byte a la vez, aumentando la huella en la memoria de la operación. Lo que me gustaría es algo como esto:Cómo dividir una matriz de bytes

byte[] largeBytes = [1,2,3,4,5,6,7,8,9]; 
byte[] smallPortion; 
smallPortion = split(largeBytes, 3); 

smallPortion sería igual 1,2,3,4
largeBytes sería igual a 5,6,7,8,9

Respuesta

14

Esta es la forma en que lo haría:

using System; 
using System.Collections; 
using System.Collections.Generic; 

class ArrayView<T> : IEnumerable<T> 
{ 
    private readonly T[] array; 
    private readonly int offset, count; 

    public ArrayView(T[] array, int offset, int count) 
    { 
     this.array = array; 
     this.offset = offset; 
     this.count = count; 
    } 

    public int Length 
    { 
     get { return count; } 
    } 

    public T this[int index] 
    { 
     get 
     { 
      if (index < 0 || index >= this.count) 
       throw new IndexOutOfRangeException(); 
      else 
       return this.array[offset + index]; 
     } 
     set 
     { 
      if (index < 0 || index >= this.count) 
       throw new IndexOutOfRangeException(); 
      else 
       this.array[offset + index] = value; 
     } 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     for (int i = offset; i < offset + count; i++) 
      yield return array[i]; 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     IEnumerator<T> enumerator = this.GetEnumerator(); 
     while (enumerator.MoveNext()) 
     { 
      yield return enumerator.Current; 
     } 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     byte[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; 
     ArrayView<byte> p1 = new ArrayView<byte>(arr, 0, 5); 
     ArrayView<byte> p2 = new ArrayView<byte>(arr, 5, 5); 
     Console.WriteLine("First array:"); 
     foreach (byte b in p1) 
     { 
      Console.Write(b); 
     } 
     Console.Write("\n"); 
     Console.WriteLine("Second array:"); 
     foreach (byte b in p2) 
     { 
      Console.Write(b); 
     } 
     Console.ReadKey(); 
    } 
} 
0

No se puede. Lo que puede querer es mantener un punto de partida y una cantidad de elementos; en esencia, construir iteradores. Si esto es C++, puede simplemente usar std::vector<int> y usar los integrados.

En C#, construiría una pequeña clase de iterador que contiene el índice de inicio, cuenta e implementa IEnumerable<>.

1

No estoy seguro de lo que entendemos por:

me gustaría dividir la matriz de bytes en un momento determinado (índice) sin tener que simplemente crear una nueva matriz de bytes y copiar cada byte a la vez, aumentando la huella en la memoria de la operación.

En la mayoría de los lenguajes, sin duda C#, una vez que se ha asignado una matriz, no hay forma de cambiar el tamaño de la misma. Parece que estás buscando una manera de cambiar la longitud de una matriz, lo que no puedes hacer. También desea reciclar de algún modo la memoria de la segunda parte de la matriz, para crear una segunda matriz, que tampoco puede hacer.

En resumen: simplemente cree una nueva matriz.

17

FYI. System.ArraySegment<T> estructura es básicamente lo mismo que ArrayView<T> en el código anterior. Puede usar esta estructura lista para usar de la misma manera, si lo desea.

+0

Interesante. Lástima que no vi este cuando estaba trabajando en ese proyecto. Gracias por la información de todos modos. –

13

En C# con LINQ se puede hacer esto:

smallPortion = largeBytes.Take(4).ToArray(); 
largeBytes = largeBytes.Skip(4).Take(5).ToArray(); 

;)

+3

El OP se está preguntando cómo hacer esto ** sin tener que crear [...] una nueva matriz de bytes y copiar cada byte a la vez ** Pero eso es exactamente lo que hace su código LINQ. Dos veces. –

+0

... esto me ayudó a resolver un problema que tuve que no se resolvió con 'ArraySegment ' .. – AceMark

+0

@Christian, para evitar el uso de la memoria adicional simplemente elimine las llamadas ".ToArray()". Eso devolverá dos IEnumerables con muchas menos líneas de código. –

3

prueba este:

private IEnumerable<byte[]> ArraySplit(byte[] bArray, int intBufforLengt) 
    { 
     int bArrayLenght = bArray.Length; 
     byte[] bReturn = null; 

     int i = 0; 
     for (; bArrayLenght > (i + 1) * intBufforLengt; i++) 
     { 
      bReturn = new byte[intBufforLengt]; 
      Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLengt); 
      yield return bReturn; 
     } 

     int intBufforLeft = bArrayLenght - i * intBufforLengt; 
     if (intBufforLeft > 0) 
     { 
      bReturn = new byte[intBufforLeft]; 
      Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLeft); 
      yield return bReturn; 
     } 
    } 
+0

Creo que debería ser estático –

0

Como Eren said, puede utilizar ArraySegment<T>. Aquí hay un método de extensión y ejemplo de uso:

public static class ArrayExtensionMethods 
{ 
    public static ArraySegment<T> GetSegment<T>(this T[] arr, int offset, int? count = null) 
    { 
     if (count == null) { count = arr.Length - offset; } 
     return new ArraySegment<T>(arr, offset, count.Value); 
    } 
} 

void Main() 
{ 
    byte[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; 
    var p1 = arr.GetSegment(0, 5); 
    var p2 = arr.GetSegment(5); 
    Console.WriteLine("First array:"); 
    foreach (byte b in p1) 
    { 
     Console.Write(b); 
    } 
    Console.Write("\n"); 
    Console.WriteLine("Second array:"); 
    foreach (byte b in p2) 
    { 
     Console.Write(b); 
    } 
} 
Cuestiones relacionadas