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

问题描述 投票:0回答:5

我试图弄清楚如何从多维数组中获取单个维度(为了论证,假设它是二维的),我有一个多维数组:

double[,] d = new double[,] { { 1, 2, 3, 4, 5 }, { 5, 4, 3, 2, 1 } };

如果它是一个锯齿状数组,我只需调用

d[0]
,这就会给我一个
{1, 2, 3, 4, 5}
数组,有没有办法用 2D 数组实现相同的效果?

c# .net arrays multidimensional-array jagged-arrays
5个回答
25
投票

不。您当然可以编写一个代表切片的包装类,并在内部具有索引器 - 但没有任何内置内容。另一种方法是编写一个方法,制作切片的copy并传回向量 - 这取决于您是否想要copy

using System;
static class ArraySliceExt
{
    public static ArraySlice2D<T> Slice<T>(this T[,] arr, int firstDimension)
    {
        return new ArraySlice2D<T>(arr, firstDimension);
    }
}
class ArraySlice2D<T>
{
    private readonly T[,] arr;
    private readonly int firstDimension;
    private readonly int length;
    public int Length { get { return length; } }
    public ArraySlice2D(T[,] arr, int firstDimension)
    {
        this.arr = arr;
        this.firstDimension = firstDimension;
        this.length = arr.GetUpperBound(1) + 1;
    }
    public T this[int index]
    {
        get { return arr[firstDimension, index]; }
        set { arr[firstDimension, index] = value; }
    }
}
public static class Program
{
    static void Main()
    {
        double[,] d = new double[,] { { 1, 2, 3, 4, 5 }, { 5, 4, 3, 2, 1 } };
        var slice = d.Slice(0);
        for (int i = 0; i < slice.Length; i++)
        {
            Console.WriteLine(slice[i]);
        }
    }
}

17
投票

那个答案的改进版本

public static IEnumerable<T> SliceRow<T>(this T[,] array, int row)
{
    for (var i = array.GetLowerBound(1); i <= array.GetUpperBound(1); i++)
    {
        yield return array[row, i];
    }
}

public static IEnumerable<T> SliceColumn<T>(this T[,] array, int column)
{
    for (var i = array.GetLowerBound(0); i <= array.GetUpperBound(0); i++)
    {
        yield return array[i, column];
    }
}

3
投票

矩形阵列不是为此目的而构建的。如果您需要这种类型的功能,您应该切换到锯齿状数组。编写一个将矩形数组转换为锯齿状数组的函数非常简单。

您还可以通过在适当的维度上调用 GetLength(int 维度)来简单地重建该数组,然后对其进行正确索引以检索每个值。它比转换整个数组更便宜,但最便宜的选择是将其更改为使用锯齿状数组。


2
投票

这应该复制锯齿状数组的 a[r] 功能:

T[] Slice<T>(T[,] a, int r) => Enumerable.Range(0, a.GetUpperBound(1) + 1).Select(i => a[r, i]).ToArray();

0
投票

已经给出了好的答案,但我最近进行了研究并将这些方法创建到我的库中:

/// <summary> Iterates the given 2-dimensional array's specified row. A row is all values contained when the left hand index is identical. </summary>
public static IEnumerable<T> IterateRow<T> (T[,] array, int row)
{
    int upperBound = array.GetUpperBound (1);
    for (int i = array.GetLowerBound (1); i <= upperBound; i++)
    {
        yield return array[row, i];
    }
}

/// <summary> Iterates the given 2-dimensional array's specified column. A column is all values contained when the right hand index is identical. </summary>
public static IEnumerable<T> IterateColumn<T> (T[,] array, int column)
{
    int upperBound = array.GetUpperBound (0);
    for (int i = array.GetLowerBound (0); i <= upperBound; i++)
    {
        yield return array[i, column];
    }
}

/// <summary> Returns the given 2-dimensional array's specified row. A row is all values contained when the left hand index is identical. </summary>
public static T[] SliceRow<T> (T[,] array, int row)
{
    int upperBound = array.GetUpperBound (1);
    T[] slice = new T[upperBound + 1];
    for (int i = array.GetLowerBound (1); i <= upperBound; i++)
    {
        slice[i] = array[row, i];
    }
    return slice;
}

/// <summary> Returns the given 2-dimensional array's specified column. A column is all values contained when the right hand index is identical. </summary>
public static T[] SliceColumn<T> (T[,] array, int column)
{
    int upperBound = array.GetUpperBound (0);
    T[] slice = new T[upperBound + 1];
    for (int i = array.GetLowerBound (0); i <= upperBound; i++)
    {
        slice[i] = array[i, column];
    }
    return slice;
}

这些稍微细化了。例如“我<= array.GetUpperBound(1)" as written in the other answer would run that method with every iteration. Also there are versions that provide the 1-dimensional arrays directly. I prefer to use the term "Iterate" in method names for iterative methods. I am also no fan of method extensions any more - you may lose overview at some point if they stack up too much. And given that you would (and should) need to add the namespace anyway, it doesn't really speed things up much. In my case I just use "int[] firstRow = UtilityFunctions.SliceRow (myArray, 0);".

© www.soinside.com 2019 - 2024. All rights reserved.