2011-06-20 56 views
6

如果我有d二維數組,我知道我可以沿行創建1D切片如下:在d切片二維數組

auto one_dim_arr=two_dim_arr[i][0..$] 

有一個簡單的方法,使沿列的1D片?有人可能會做什麼

auto one_dim_arr=two_dim_arr[0..$][j] 

會做什麼?

回答

4

下面是該用戶創建的類型可能是什麼樣子:

// Demo 

void main() 
{ 
    int[3][3] arr = [ 
     [1, 2, 3], 
     [4, 5, 6], 
     [7, 8, 9], 
    ]; 

    // simple creation 
    auto middleColumn = verticalSlice(arr, 1); 
    assert(middleColumn[1] == 5); 

    // iteratable 
    foreach (i, v; middleColumn) 
     assert(v == 2+i*3); 

    // still a slice - writing will change original array 
    middleColumn[1] = 17; 
    assert(arr[1][1] == 17); 

    // sliceable itself 
    auto center = middleColumn[1..2]; 
    center[0] = 42; 
    assert(arr[1][1] == 42); 

    // get a normal array with .dup 
    int[] copyOfMiddleColumn = middleColumn.dup; 
} 

// Implementation 

struct StepSlice(T) 
{ 
    T* ptr; 
    size_t length, step; 

    T opIndex(size_t index) 
    in { assert(index<length); } 
    body { return ptr[step*index]; } 

    void opIndexAssign(T value, size_t index) 
    in { assert(index<length); } 
    body { ptr[step*index] = value; } 

    StepSlice!T opSlice(size_t start, size_t end) 
    in { assert(start<=end && end<=length); } 
    body { return StepSlice!T(ptr+start*step, end-start, step); } 

    int opApply(int delegate(ref T) dg) 
    { 
     int result = 0; 

     for (size_t i=0; i<length; i++) 
     { 
      result = dg(ptr[i*step]); 
      if (result) 
       break; 
     } 
     return result; 
    } 

    int opApply(int delegate(ref size_t, ref T) dg) 
    { 
     int result = 0; 

     for (size_t i=0; i<length; i++) 
     { 
      result = dg(i, ptr[i*step]); 
      if (result) 
       break; 
     } 
     return result; 
    } 

    T[] dup() 
    { 
     T[] result = new T[length]; 
     for (size_t i=0; i<length; i++) 
      result[i] = ptr[i*step]; 
     return result; 
    } 
} 

StepSlice!T verticalSlice(T, size_t W)(T[W][] arr, size_t column) 
{ 
    return StepSlice!T(arr[0].ptr+column, arr.length, W); 
} 

我認爲這是缺少範圍原語,但仍然是一個很好的起點。


隨着std.range.stride

import std.range; 

// Demo 

void main() 
{ 
    int[3][3] arr = [ 
     [1, 2, 3], 
     [4, 5, 6], 
     [7, 8, 9], 
    ]; 

    // simple creation 
    auto middleColumn = verticalSlice(arr, 1); 
    assert(middleColumn[1] == 5); 

    // iteratable 
    uint i; 
    foreach (v; middleColumn) 
     assert(v == 2+(i++)*3); 

    // still a slice - writing will change original array 
    middleColumn[1] = 17; 
    assert(arr[1][1] == 17); 

    // sliceable itself 
    auto center = middleColumn[1..2]; 
    center[0] = 42; 
    assert(arr[1][1] == 42); 

    // get a normal array with array() 
    int[] copyOfMiddleColumn = array(middleColumn); 
} 

// Implementation 

auto verticalSlice(T, size_t W)(T[W][] arr, size_t column) 
{ 
    T* start = arr[0].ptr+column; 
    return stride(start[0..W*arr.length], W); 
} 
+2

@Haunter:在這裏有任何幫助嗎? – Mehrdad

+1

是啊!我正在尋找那樣的東西。 –

+1

大聲笑,這是我第一次看到一個被接受的答案被轉移到它原來的同一個人身上...... – Mehrdad

3

不,這是不可能的。爲了這個工作,D片需要有一個步驟。可以創建一個類似於切片的自定義類型(例如std.algorithm.map)。

請注意,上面的建議語法可以編譯得很好,但是沒有你要找的效果。

+1

你是什麼意思的「D片需要有一個步驟」?我不太明白。 –

+0

「一步」是什麼意思? – Dan

+2

如果您知道如何在內存中表示二維數組以及切片如何工作,您將知道該程序需要知道每行中同一列上的元素之間的距離。這就是我所說的「步驟」。當前D切片具有一個隱含的步驟。 –

2

如果輸入是一個T[][](即動態陣列的動態陣列)和要用作輸出,可以分配一個新的「外部」陣列相同,並且用內部數組的切片填充它。這將導致O(n) op,其中正常切片是O(1) op。編碼留給讀者作爲練習。