【问题标题】:How to copy a row of values from a 2D array into a 1D array?如何将一行值从二维数组复制到一维数组中?
【发布时间】:2010-10-22 07:01:53
【问题描述】:

我们有以下对象

int [,] oGridCells;

仅与固定的第一个索引一起使用

int iIndex = 5;
for (int iLoop = 0; iLoop < iUpperBound; iLoop++)
{
  //Get the value from the 2D array
  iValue = oGridCells[iIndex, iLoop];

  //Do something with iValue
}

.NET 中是否有办法将固定第一个索引处的值转换为一维数组(不是通过循环值)?

如果数组只被循环一次,我怀疑它会加速代码(而且它可能会使其变慢)。但是如果数组被大量操作,那么单维数组将比多维数组更有效。

我问这个问题的主要原因是看看它是否可以完成以及如何完成,而不是将其用于生产代码。

【问题讨论】:

    标签: c# .net arrays multidimensional-array


    【解决方案1】:

    如果可能的话,我会感到惊讶:我敢打赌,oGridCells[iIndex, iLoop] 只是oGridCells[iIndex * iLoop] 的一种简写形式(在内部,在 MSIL 中),而多维数组是为此的语法糖。

    要回答您的问题:不。您必须循环这些值。

    【讨论】:

    • 它们是与一维数组不同的类型。零索引一维数组是向量类型,而所有其他数组都是数组类型。所以不是语法糖。
    【解决方案2】:

    编辑:

    我意识到有办法!诚然,这可能不值得。使用unsafe code。完整示例,显示两种方式,以下不安全:

    public class MultiSingleUnsafe
    {
        public static unsafe void Main(String[] a)
        {
        int rowCount = 6;
        int iUpperBound = 10;
        int [,] oGridCells = new int[rowCount, iUpperBound];
    
        int iIndex = rowCount - 2; // Pick a row.
    
        for(int i = 0; i < iUpperBound; i++)
        {
            oGridCells[iIndex, i] = i;
        }
    
        for (int iLoop = 0; iLoop < iUpperBound; iLoop++)
        {
            //Get the value from the 2D array
            int iValue = oGridCells[iIndex, iLoop];
            Console.WriteLine("Multi-dim array access iValue: " + iValue);
            //Do something with iValue
        }
        
        fixed(int *lastRow = &(oGridCells[iIndex,0]))
        {   
            for (int iLoop = 0; iLoop < iUpperBound; iLoop++)
            {
            int iValue = lastRow[iLoop];
            Console.WriteLine("Pointer access iValue: " + iValue);
            }
        }
        }
    }
    

    我不知道在 C# 中将多维数组转换为一维数组。当然,您可以创建一个新的一维数组并复制到其中。但我认为即使您多次循环这些值,这也不会带来性能优势。正如达伦所说,无论如何,内部都是指针算术。如果您想确定,请对其进行分析。

    【讨论】:

    • 我不是在找演员,我知道那是不可能的。
    【解决方案3】:

    以下代码演示了将 16 个字节(4 个整数)从二维数组复制到一维数组。

    int[,] oGridCells = {{1, 2}, {3, 4}};
    int[] oResult = new int[4];
    System.Buffer.BlockCopy(oGridCells, 0, oResult, 0, 16);
    

    您还可以通过提供正确的字节偏移量来选择性地仅复制数组中的 1 行。此示例复制 3 行二维数组的中间行。

    int[,] oGridCells = {{1, 2}, {3, 4}, {5, 6}};
    int[] oResult = new int[2];
    System.Buffer.BlockCopy(oGridCells, 8, oResult, 0, 8);
    

    【讨论】:

    • 这无法获得所需的结果,因为它复制了所有值,而不仅仅是第一个索引 0 或 1 中的值。
    • 我添加了一个复制 1 行的示例。
    • 要使用此方法,您需要计算数组的边界以获得偏移量。这对于多维数组来说是低效的。但它看起来确实可行。
    • 它有什么低效之处?元素的大小乘以每行的元素数乘以行索引就是偏移量。如果你的行索引没有改变,你只需要计算一次偏移量。
    • 同意,我想您将不得不调用效率低下的方法来找到能够循环遍历问题源代码中的元素的上限。不过,您的代码看起来不太正确,您的数组是 int [2, 3] 所以一行数据在索引 0 或 1 处是 int[3]。
    【解决方案4】:

    您无法获得对每个数组的引用。但是,您可以使用jagged array

    【讨论】:

    • 同意,如果我要重写代码(这不是一个选项),我会使用锯齿状数组。尤其是锯齿状数组的性能优于多维数组。
    【解决方案5】:

    “但是如果数组被大量操作,那么单维数组将比多维数组更有效。”

    我在去年夏天对这个进行了一些分析,并惊讶地发现 2D 和 1D 阵列之间的性能没有显着差异。

    我没有测试锯齿状数组的性能。

    【讨论】:

    • 它们是不同的类型,某些操作(例如测试长度)可能会明显变慢。锯齿状阵列提供了两全其美的效果。
    【解决方案6】:

    你可以试试这个:

     int[,] twoD = new int[2,2];
     twoD[0, 0] = 1;
     twoD[0, 1] = 2;
     twoD[1, 0] = 3;
     twoD[1, 1] = 4;
    
     int[] result = twoD.Cast<int>().Select(c => c).ToArray();
    

    结果将是一个带有数据的整数数组:

    1, 2, 3, 4
    

    【讨论】:

    • 你为什么使用 Select?
    • 如果你愿意,你可以删除选择,它仍然可以。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-02
    • 2021-12-31
    • 1970-01-01
    • 1970-01-01
    • 2014-09-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多