2011-06-20 33 views
6

Nếu tôi có một mảng 2D trong D, tôi biết rằng tôi có thể tạo 1D lát cùng hàng như sau:mảng Cắt lát 2D trong D

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

là có một cách đơn giản để thực hiện một lát 1D cùng cột? Điều gì đó có thể làm cho những gì người ta có thể nghĩ

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

sẽ làm gì?

Trả lời

4

Đây là những gì một loại người dùng tạo cho điều này có thể trông giống như:

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

Tôi nghĩ đó là nguyên thủy loạt mất tích, nhưng vẫn là một điểm khởi đầu tốt.


Với 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: Liệu có thể có sự giúp đỡ nào ở đây không? – Mehrdad

+1

Vâng! Tôi đang tìm kiếm một thứ như thế. –

+1

Lol, đây là lần đầu tiên tôi nhìn thấy một câu trả lời được chấp nhận được chuyển giao cho cùng một người nó đã được ban đầu từ ... – Mehrdad

3

Không, không thể. Để làm việc này, D lát sẽ cần phải có một bước. Có thể tạo loại tùy chỉnh hoạt động tương tự như một lát (ví dụ: std.algorithm.map).

Lưu ý rằng cú pháp được đề xuất ở trên sẽ biên dịch tốt, nhưng không có hiệu ứng bạn đang tìm kiếm.

+1

Ý bạn là gì bởi "D lát sẽ cần phải có một bước"? Tôi không hiểu lắm. –

+0

Bạn có ý nghĩa gì với "một bước"? – Dan

+2

Nếu bạn biết cách các mảng bidimensional được biểu diễn trong bộ nhớ và cách các slice hoạt động, bạn sẽ biết rằng chương trình sẽ cần biết khoảng cách giữa các phần tử trên cùng một cột từ mỗi hàng. Đây là những gì tôi có nghĩa là "bước". D lát hiện tại có một bước ngụ ý của một. –

2

Nếu đầu vào của bạn là một T[][] (tức là một mảng động của mảng động) và bạn muốn giống như đầu ra, bạn có thể phân bổ một 'bên ngoài' mảng mới và điền nó với các lát của mảng bên trong. Điều này sẽ dẫn đến một op O(n) nơi như một lát bình thường là một O(1) op. Việc viết mã được để lại như một bài tập cho người đọc.