如何从C#中的2D数组中获取完整的行或列

Use*_*892 27 c# multidimensional-array

我不想使用锯齿状数组,我有一个2D数组,我想得到一个完整的列或行而不通过它循环.有没有人知道如何做到这一点.

double [,]  array = new double [3,3] ;

1   2   3 
4   5   6

Out: 1   2   3  or 2   5 
Run Code Online (Sandbox Code Playgroud)

小智 29

要从多维数组中获取特定的行或列,可以使用一些LINQ:

public class CustomArray<T>
{
    public T[] GetColumn(T[,] matrix, int columnNumber)
    {
        return Enumerable.Range(0, matrix.GetLength(0))
                .Select(x => matrix[x, columnNumber])
                .ToArray();
    }

    public T[] GetRow(T[,] matrix, int rowNumber)
    {
        return Enumerable.Range(0, matrix.GetLength(1))
                .Select(x => matrix[rowNumber, x])
                .ToArray();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案 - 它是通用的、优雅的,并且允许不需要枚举整个结果列表的查询。 (3认同)
  • 与接受的答案不同,这适用于“bool”以及非原始类型 (2认同)
  • 从概念上讲,你没有把这个搞混吗?代码不应该有:矩阵[columnNumber,x]和矩阵[x,rowNumber]吗?大多数人从概念上会认为一维数组是单“行”和多列,而二维数组是具有多行。毕竟,列数是 X 轴,行数是 Y 轴。 (2认同)
  • _低语:使用扩展方法,而不是新类。_ (2认同)

Mat*_*son 12

您可以通过使用来优化它以获取行Buffer.BlockCopy(),但是要获得一个您必须循环的列.Buffer.BlockCopy()最终使用处理器指令来复制内存块,所以它非常快.

将代码放入扩展方法以便于调用更方便.请注意,Buffer.BlockCopy()只能在基本类型,数组中使用,即int,double,char等等.这不包括string.

这是一个可编辑的例子:

using System;
using System.Linq;
using System.Runtime.InteropServices;

namespace ConsoleApplication4
{
    public static class Program
    {
        private static void Main()
        {
            var array = new [,]
            {
                {0.1, 0.2, 0.3, 0.4, 0.5},
                {1.1, 1.2, 1.3, 1.4, 1.5},
                {2.1, 2.2, 2.3, 2.4, 2.5},
                {3.1, 3.2, 3.3, 3.4, 3.5},
            };

            var row = array.GetRow(2);

            // This prints 2.1, 2.2, 2.3, 2.4, 2.5

            Console.WriteLine(string.Join(", ", row.Select(element => element.ToString())));
        }
    }

    public static class ArrayExt
    {
        public static T[] GetRow<T>(this T[,] array, int row)
        {
            if (!typeof(T).IsPrimitive)
                throw new InvalidOperationException("Not supported for managed types.");

            if (array == null)
                throw new ArgumentNullException("array");

            int cols = array.GetUpperBound(1) + 1;
            T[] result = new T[cols];

            int size;

            if (typeof(T) == typeof(bool))
                size = 1;
            else if (typeof(T) == typeof(char))
                size = 2;
            else
                size = Marshal.SizeOf<T>();

            Buffer.BlockCopy(array, row*cols*size, result, 0, cols*size);

            return result;
        }
   }
}
Run Code Online (Sandbox Code Playgroud)

  • @BCA 是的,因为 Marshal.SizeOf(bool) 是 4,而不是 1。我已经通过明确检查该类型并使用大小 1(如果它是 bool)来解决这个问题。`char` 也失败了,所以我也对此进行了修复。 (2认同)

Ale*_*x23 9

截至 2021 年 3 月,您现在可以使用非常酷的 Span2D 类来实现此目的!

如果您喜欢使用跨度(我强烈建议您阅读它们,它们非常棒),您可以使用以下代码

var span2D = new Span2D<double>(array);

//Gets the first row and returns a span of it
var rowSpan = span2D.GetRowSpan(0);

foreach(var number in rowSpan)
{
    //Do something with numbers
}

//Gets the 2nd Column as a RefEnumerable and converts it to an array
var column = span2D.GetColumn(1).ToArray();
Run Code Online (Sandbox Code Playgroud)