2008-08-21 36 views
26

Mam tablicę bajtów w pamięci, odczytuję z pliku. Chciałbym podzielić tablicę bajtów w pewnym punkcie (indeksie) bez konieczności tworzenia nowej tablicy bajtów i kopiowania każdego bajtu w tym samym czasie, zwiększając wydruk stopy operacji w pamięci. Chciałbym coś takiego:Jak podzielić tablicę bajtów

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

smallPortion wyniesie 1,2,3,4
largeBytes wyniesie 5,6,7,8,9

Odpowiedz

14

To w jaki sposób to zrobić:

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

Nie możesz. To, czego możesz chcieć, to zachować punkt początkowy i liczbę przedmiotów; w istocie buduj iteratory. Jeśli to jest C++, możesz po prostu użyć std::vector<int> i użyć wbudowanych.

W języku C# zbudowałem małą klasę iteratora, która przechowuje indeks początkowy, liczy i implementuje IEnumerable<>.

1

Nie jestem pewien co masz na myśli przez:

Chciałbym podzielić tablicy bajtowej w pewnym momencie (index) bez konieczności tworzenia nowej tablicy bajtów i kopiowania każdego bajtu na raz, zwiększając wydruk stopy operacji w pamięci.

W większości języków, z pewnością C#, po przydzieleniu tablicy, nie ma możliwości zmiany jej rozmiaru. Wygląda na to, że szukasz sposobu na zmianę długości tablicy, której nie możesz. Chcesz także jakoś odtworzyć pamięć dla drugiej części tablicy, aby utworzyć drugą tablicę, której również nie możesz wykonać.

Podsumowując: po prostu utwórz nową tablicę.

17

FYI. System.ArraySegment<T> struktura w zasadzie jest tym samym, co ArrayView<T> w powyższym kodzie. Możesz użyć tej gotowej struktury w ten sam sposób, jeśli chcesz.

+0

Interesujące. Szkoda, że ​​nie widziałem tego podczas pracy nad tym projektem. Dzięki za informacje. –

13

W języku C# z LINQ można to zrobić:

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

;)

+3

OP zastanawia się, jak to zrobić ** bez konieczności [...] tworzenia nowej tablicy bajtów i kopiowania każdego bajtu w tym czasie ** Ale to właśnie robi twój kod LINQ. Dwa razy. –

+0

.. Pomogło mi to rozwiązać problem, który nie został rozwiązany przez 'ArraySegment ' .. – AceMark

+0

@Christian, aby uniknąć korzystania z pamięci adittional po prostu usuń oba wywołania ".ToArray()". To zwróci dwa IEnumerables z dużo mniejszymi liniami kodu. –

3

Spróbuj tego:

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

Myślę, że powinien być statyczny –

0

Jak Eren said, można użyć ArraySegment<T>. Oto metoda rozszerzenia i przykład użycia:

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); 
    } 
}