2011-06-20 12 views
6

Jeśli mam 2D ​​tablicy w D, wiem, że mogę tworzyć plastry 1D wzdłuż rzędów, co następuje:tablice Odcinanie 2D D

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

to istnieje prosty sposób dokonać 1D kawałek wzdłuż kolumn? Coś, co robi to, co ktoś mógłby pomyśleć: czy zrobiłby to, co można by pomyśleć?

Odpowiedz

4

Oto co typ tworzone przez użytkowników za to może wyglądać:

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

myślę, że brakuje prymitywy zakres, ale mimo to dobry punkt wyjścia.


Z 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: Czy "przydałby się" tu jakakolwiek pomoc? – Mehrdad

+1

Tak! Szukałem czegoś takiego. –

+1

Lol, po raz pierwszy widziałem, że zaakceptowana odpowiedź została przeniesiona na tę samą osobę, z której pochodził ... – Mehrdad

3

Nie, to niemożliwe. Aby to działało, plasterki D musiałyby mieć jeden krok. Możliwe jest utworzenie niestandardowego typu, który działa podobnie do plasterka (na przykład std.algorithm.map).

Należy zauważyć, że sugerowana powyżej składnia zostałaby skompilowana poprawnie, ale nie przyniesie pożądanego efektu.

+1

Co masz na myśli, mówiąc, że "plasterki D powinny mieć krok"? Nie bardzo to rozumiem. –

+0

Co masz na myśli mówiąc "krok"? – Dan

+2

Jeśli wiesz, jak wielowymiarowe tablice są reprezentowane w pamięci i jak działają plasterki, będziesz wiedzieć, że program będzie musiał znać odległość między elementami w tej samej kolumnie z każdego wiersza. To właśnie miałem na myśli przez "krok". Obecne wycinki D mają implikowany krok jeden. –

2

Jeśli wejście jest T[][] (czyli dynamicznej tablicy dynamicznych tablic) i chcesz tak samo jak wyjście, można przydzielić nową „zewnętrzną” tablicę i wypełnij go plasterkami wewnętrznych tablic. Spowoduje to powstanie O(n) op, gdzie jako normalny przekrój jest O(1) op. Kodowanie jest pozostawione jako ćwiczenie dla czytelnika.