在 D 中切片二维数组

Posted

技术标签:

【中文标题】在 D 中切片二维数组【英文标题】:Slicing 2D arrays in D 【发布时间】:2011-09-19 02:30:31 【问题描述】:

如果我在 D 中有一个二维数组,我知道我可以沿行创建一维切片,如下所示:

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

有没有一种简单的方法可以沿列制作一维切片?做某件事的人可能会想的事情

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

会吗?

【问题讨论】:

【参考方案1】:

这是用户为此创建的类型可能的样子:

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

【讨论】:

@Haunter:stride 在这里有什么帮助吗? 是的!我正在寻找类似的东西。 大声笑,这是我第一次看到一个接受的答案被转移给原来的同一个人......【参考方案2】:

不,这是不可能的。为此,D 切片需要有一个步骤。可以创建与切片类似的自定义类型(例如 std.algorithm.map)。

请注意,您上面建议的语法可以正常编译,但没有您想要的效果。

【讨论】:

“D 切片需要有一个步骤”是什么意思?我不太明白。 “一步”是什么意思? 如果你知道二维数组在内存中是如何表示的以及切片是如何工作的,你就会知道程序需要知道每一行同一列上的元素之间的距离。这就是我所说的“步”。当前的 D 切片有一个隐含的步长。 我不确定这是否可以在许多其他语言中实现,是吗? IIRC,Python 允许通过一个步骤对字符串和数组进行切片,但它会复制数据而不是创建类似 D 的切片。在 C++ 中也可以实现自定义类型。【参考方案3】:

如果您的输入是 T[][](即动态数组的动态数组)并且您希望与输出相同,则可以分配一个新的“外部”数组并用内部数组的切片填充它。这将导致O(n) 操作,其中正常切片是O(1) 操作。编码留给读者作为练习。

【讨论】:

以上是关于在 D 中切片二维数组的主要内容,如果未能解决你的问题,请参考以下文章

如何从多维数组中获取维度(切片)

Numpy - 从数组中切片二维行或列向量

在 Perl 中修改然后切片未知大小的二维数组

cython中的二维数组切片

c++ vector二维数组初始化与vector切片

c++ vector二维数组初始化与vector切片