【问题标题】:What's the best way to extract a one-dimensional array from a rectangular array in C#?从 C# 中的矩形数组中提取一维数组的最佳方法是什么?
【发布时间】:2010-09-18 22:53:07
【问题描述】:

假设我有一个矩形字符串数组 - 不是锯齿状数组

string[,] strings = new string[8, 3];

从中提取一维数组(单行或单列)的最佳方法是什么?当然,我可以使用 for 循环来做到这一点,但我希望 .NET 有一个更优雅的内置方式。

将提取的字符串数组转换为对象数组的奖励积分。

【问题讨论】:

    标签: c# .net arrays casting


    【解决方案1】:

    您可以轻松地将字符串数组转换为对象数组 - 换一种方式是行不通的。实际提取必须使用 for 循环,据我所见:Array.Copy 要求源和目标等级相同,Buffer.BlockCopy 仅适用于值类型数组。不过看起来确实很奇怪……

    您可以使用 LINQ 在单个语句中添加一行或一列,尽管它效率低下(因为它会在内部构建一个列表,然后必须将其转换为一个数组 - 如果您自己这样做,您可以将数组预分配到正确的大小并直接复制)。

    复制一行(rowNum是要复制的行):

    object[] row = Enumerable.Range(0, rowLength)
                             .Select(colNum => (object) stringArray[rowNum, colNum])
                             .ToArray();
    

    复制一列(colNum是要复制的列):

    object[] column = Enumerable.Range(0, columnLength)
                                .Select(rowNum => (object) stringArray[rowNum, colNum])
                                .ToArray();
    

    我不确定这是否真的比 foreach 循环更好/更简单 - 特别是如果您编写 ExtractRow 方法和 ExtractColumn 方法并重用它们。

    【讨论】:

    • 只是确保我没有重新发明轮子。这个特定的任务在自然界中发生的频率肯定不足以保证内置函数。
    • 我不知道——我认为框架支持的东西更多。我仍然对没有行副本感到有点惊讶(因为那应该是 blittable)。
    【解决方案2】:

    对于矩形数组:

    string[,] rectArray = new string[3,3] { 
        {"a", "b", "c"}, 
        {"d", "e", "f"}, 
        {"g", "h", "i"} };
    
    var rectResult = rectArray.Cast<object>().ToArray();
    

    对于锯齿状数组:

    string[][] jaggedArray =  { 
        new string[] {"a", "b", "c", "d"}, 
        new string[] {"e", "f"}, 
        new string[] {"g", "h", "i"} };
    
    var jaggedResult = jaggedArray.SelectMany(s => s).Cast<object>().ToArray();
    

    【讨论】:

      【解决方案3】:

      我想澄清一下(给出示例和所问的内容)。

      锯齿状数组是一个数组数组,声明如下:

      string[][] data = new string[3][];
      data[0] = new string[] { "0,[0]", "0,[1]", "0,[2]" };
      data[1] = new string[] { "1,[0]", "1,[1]", "1,[2]" ];
      data[2] = new string[] { "2,[0]", "1,[1]", "1,[2]" };
      

      矩形数组 被定义为包含多个维度的单个数组:

      string[,] data = new string[3,3];
      data[0,0] = "0,0";
      data[0,1] = "0,1";
      data[0,2] = "0,2";
      ...etc
      

      因此,锯齿状数组 是 IQueryable/IEnumerable,因为您可以对其进行迭代以在每次迭代时接收一个数组。而 矩形数组 不是在这种情况下,将无法使用 Linq 或为 Array 创建的任何预定义函数。

      虽然您可以像这样遍历数组一次(并实现您想要的):

      /// INPUT: rowIndex, OUTPUT: An object[] of data for that row
      int colLength = stringArray.GetLength(1);
      object[] rowData = new object[colLength];
      for (int col = 0; col < colLength; col++) {
          rowData[col] = stringArray[rowIndex, col] as object;
      }
      return rowData;
      
      /// INPUT: colIndex, OUTPUT: An object[] of data for that column
      int rowLength = stringArray.GetLength(0);
      object[] colData = new object[rowLength];
      for (int row = 0; r < rowLength; row++) {
          colData[row] = stringArray[row, colIndex] as object;
      }
      return colData;
      

      希望这会有所帮助:)

      【讨论】:

      • 这不是真的。如here 所述,数组类型派生自基类型Array,它确实实现了 IEnumerable。所以你可以使用一些 Linq 方法,而不是全部。例如 Cast() 工作正常。
      【解决方案4】:

      LINQ 就是答案

      static object[] GetColumn(string[][] source, int col) {
          return source.Iterate().Select(x => source[x.Index][col]).Cast<object>().ToArray();
      }
      static object[] GetRow(string[][] source, int row) {
          return source.Skip(row).First().Cast<object>().ToArray();
      }
      public class Pair<T> {
          public int Index;
          public T Value;
          public Pair(int i, T v) {
              Index = i;
              Value = v;
          }
      }
      static IEnumerable<Pair<T>> Iterate<T>(this IEnumerable<T> source) {
          int index = 0;
          foreach (var cur in source) {
              yield return new Pair<T>(index, cur);
              index++;
          }
      }
      

      【讨论】:

      • 我不认为这符合要求(“单行或单列”)。
      • LINQ 内部不会使用循环吗?
      • 感谢乔恩指出这一点。我读过了答案的那一部分。
      【解决方案5】:

      可以使用 Array.Copy 轻松复制行:

              int[][] arDouble = new int[2][];
              arDouble[0] = new int[2];
              arDouble[1] = new int[2];
              arDouble[0][0] = 1;
              arDouble[0][1] = 2;
              arDouble[1][0] = 3;
              arDouble[1][1] = 4;
      
              int[] arSingle = new int[arDouble[0].Length];
      
              Array.Copy(arDouble[0], arSingle, arDouble[0].Length);
      

      这会将第一行复制到单个维度数组中。

      【讨论】:

      • 这不适用于两个维度数组,如上面 nyxtom 的回答所示。
      • 我猜术语是“矩形阵列”,而不是“二维”
      • 我将问题编辑为使用“矩形”而不是“二维”。
      【解决方案6】:

      我做了扩展方法。我不知道性能。

      public static class ExtensionMethods 
      {
           public static string[] get1Dim(this string[,] RectArr, int _1DimIndex , int _2DimIndex   )
           {
              string[] temp = new string[RectArr.GetLength(1)];
      
              if (_2DimIndex == -1)
              {
                for (int i = 0; i < RectArr.GetLength(1); i++)
                {   temp[i] = RectArr[_1DimIndex, i];    }
              }
              else
              {
                for (int i = 0; i < RectArr.GetLength(0); i++)
                {   temp[i] = RectArr[  i , _2DimIndex];    }
              }
      
               return temp;
            }
      }
      

      用法

      // we now have this funtionaliy RectArray[1, * ]  
      //                                       -1 means ALL    
      string[] _1stRow = RectArray.get1Dim( 0, -1) ;    
      string[] _2ndRow = RectArray.get1Dim( 1, -1) ; 
      
      string[] _1stCol = RectArray.get1Dim( -1, 0) ;    
      string[] _2ndCol = RectArray.get1Dim( -1, 1) ; 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-11
        • 2012-08-30
        • 2013-08-19
        • 1970-01-01
        • 1970-01-01
        • 2021-05-20
        • 1970-01-01
        • 2010-09-25
        相关资源
        最近更新 更多