2015-06-01 4 views
6

Мой вопрос похож на Getting a sub-array from an existing array, хотя в моем случае очень важно другое понятие - я не могу использовать копирование памяти.Как получить подматрицу из существующего массива в C# без копирования?

Скажем, у меня есть массив X из 10000 элементов, мне нужно массив, который содержит Y бы 9000 элементов из X, начиная с X «s индекс 500.

Но я не хочу, чтобы скопировать часть X в новый массив Y, поэтому я не хочу использовать Array.Copy, Array.Clone, System.Block.Copy, IEnumerables и т. д. Я хочу, чтобы Y был ссылкой на X - Y[0], был бы фактически X[500], Y[1] соответствует X[501], .. ., Y[9000] есть X[9500].

Таким образом, например, значение изменения X[100] в то же время изменит значение Y[600]. Как я могу достичь этого в C#?

+0

Конечно, вы можете использовать операции 'unsafe' (например, указатели C++), но это не рекомендуется. –

+2

Вы считали создание простой оболочки, которая действует как массив? Это не будет * быть * массивом, но если вы написали свой код для использования обертки, вместо этого вы могли бы создать обертки для меньших фрагментов базового большего массива. –

+0

* Почему * вы не можете использовать копирование памяти? Есть ли причина, по которой вы не можете передать смещение (возможно, как часть обертки, как предлагает @ LasseV.Karlsen)? –

ответ

7

Вы можете обернуть его в другом объекте с чем-то вроде этого:

class View<T> 
{ 
    private T[] _array; 
    private long _start; 
    private long _length; 
    public View(T[] array, long start, long length) { ... } 
    public T this[long index] 
    { 
     get 
     { 
      if (/*do bounds check here*/) 
      { 
       return _array[_start + index]; 
      }  
     } 
    } 
} 

Это не будет массивом, а проекция одной.

+1

Я не думаю, что индексы массива могут быть длинными, только ints (в числе которых есть), и я бы сделал представление структурой, так как он эффективно удерживает 2 32-битных значения + ссылку на память, делает ее еще дешевле. Кроме того, я бы сделал поля только для чтения, но кроме этого, это именно то решение, которое я бы выбрал. –

+0

Спасибо, выглядит очень многообещающе :) – xcoder37

+1

@ xcoder37 Для полноты добавьте поддержку 'IEnumerable ' и' IList 'также. –

2

Вы можете использовать ArraySegment. Вот пример:

String[] X = { "one", "two", "three", "four", "five"}; 

ArraySegment<String> arraySegment = new ArraySegment<String>(X, 1,3); // will contain {"two", "three", "four"} 
arraySegment.Array[arraySegment.Offset + 1] = "3"; // X will contain { "one", "two", "3", "four", "five"}; 
          // and arraySegment.Array will contain {"two", "3", "four"} 
0

К сожалению ArraySegment<T> уплотняется, иначе вы можете легко расширить его с помощью правильного массива-синтаксиса, т.е. индексаторах и любит.

Если бы я был вами, я бы пошел с ArraySegment<T>, и если у него нет надлежащих требований, например, ElementAt(n), чтобы быть неэффективным, просто реализуйте лучшую реализацию. Пример:

public static class ArrayExtensions 
{ 
    // Getter using underlying array 
    public static T GetValueAt<T>(this ArraySegment<T> array, int index) 
    { // No safe checks here, would recommend them in production though 
    return array.Array[array.Offset + index]; 
    } 
    // Setter using underlying array 
    public static void SetValueAt<T>(this ArraySegment<T> array, int index, T value) 
    { // maybe we should check that the calculated index is valid? Or just blow up? 
    array.Array[array.Offset + index] = value; 
    } 
} 
Смежные вопросы