用于选择数组维度的快速代码

时间:2018-04-08 22:53:47

标签: c# arrays

我有这段代码

private int[, ,] dim(int[] m)
{

    ll = 0;
    ww = 0;
    hh = 0;           

    //  int[, ,] buff3D = new int[ll, ww, hh];
    int[, ,] to3dimen = new int[ww, ll, hh];

    if ((mm == 1) || (mm == 4) || (mm == 7))
    {
        ww = 4; ll = 8; hh = 8;
        to3dimen = new int[ww, ll, hh];
        to3dimen = To3D(m, ww, ll, hh);

    }
    else if ((mm == 2) || (mm == 5) || (mm == 8))
    {
        ww = 8; ll = 4; hh = 8;
        to3dimen = new int[ww, ll, hh];
        to3dimen = To3D(m, ww, ll, hh);
    }
    else if ((mm == 3) || (mm == 6) || (mm == 9))
    {
        ww = 8; ll = 8; hh = 4;
        to3dimen = new int[ww, ll, hh];
        to3dimen = To3D(m, ww, ll, hh);
    }

    return to3dimen;
}

private int[, ,] To3D(
    int[] thisArray, 
    int width, 
    int height, 
    int hig
)
{

    int[, ,] array3d = new int[width, height, hig];

    int sum = 0;
    for (int row = 0; row < width; row++)
    {
        for (int col = 0; col < height; col++)
        {
            for (int wid = 0; wid < hig; wid++)
            {
                array3d[row, col, wid] = thisArray[sum];
                sum++;
            }
        }
    }

    return array3d;
}

函数To3d将1D数组转换为3D数组,函数dim决定3D数组的尺寸是什么(4,8,8或8,8,4或8,4, 8)。

代码工作正常,但执行时间太长(根据文件长度而有所不同)。

如果有可能,我想要一个更快的代码,有人可以帮忙吗? 注意:我考虑过parallel,但这对我的代码没用。

2 个答案:

答案 0 :(得分:4)

这里有很多多余的代码。您只需要to3dimen To3D()函数内的一个分配。

但这并不是让你失望的原因。什么让你失望的是使用多维数组。

对于初学者,请将Dim()清理为

private int[,,] Dim(int[] m)
{

    // mm   ww  ll  hh      offset=(mm-1)%3
    //  1   4   8   8       0
    //  2   8   4   8       1
    //  3   8   8   4       2
    //  4   4   8   8       0
    //  5   8   4   8       1
    //  6   8   8   4       2
    //  7   4   8   8       0
    //  8   8   4   8       1
    //  9   8   8   4       2

    int offset = (mm - 1) % 3;
    int ww = offset == 0 ? 4 : 8;
    int ll = offset == 1 ? 4 : 8;
    int hh = offset == 2 ? 4 : 8;

    return To3D(m, ww, ll, hh);

}

但要利用的强大功能,您应该创建一个类包或将三个坐标解包为单个数组索引。请考虑以下示例代码:

public class Packed3dArray : IEnumerable<int>
{
    readonly int width, height, hig;
    readonly int[] array;

    public Packed3dArray(int[] array, int mm)
    {
        int offset = (mm - 1) % 3;
        this.width = offset == 0 ? 4 : 8;
        this.height = offset == 1 ? 4 : 8;
        this.hig = offset == 2 ? 4 : 8;
        this.array = array;
    }
    #region Properties
    public int Width => width;
    public int Height => height;
    public int Hig => hig;
    public int Index(int row, int col, int wid) => wid + hig*(col + height*row);

    /// <summary>
    /// Default indexer with three coordinates
    /// </summary>
    public int this[int row, int col, int wid]
    {
        // this is really fast because it is integer math
        // and accesses a 1D array which is recommended.
        get => array[wid + hig*(col + height*row)];
        set => array[wid + hig*(col + height*row)] = value;
    }

    /// <summary>
    /// Default indexer with an index
    /// </summary>
    public int this[int index] 
    {
        get => array[index];
        set => array[index]=value;
    }

    #endregion
    public IEnumerator<int> GetEnumerator()
    {
        for (int i = 0; i < array.Length; i++)
        {
            yield return array[i];
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

用作

static void Main(string[] args)
{
    int[] array = new int[8 * 8 * 4];
    // Use mm=3
    Packed3dArray pa = new Packed3dArray(array, 3);
    int width = pa.Width    // width = 8
    int height = pa.Height  // height = 8
    int hig = pa.Hig        // hig = 4    

    // Set the last element to one using the default indexer (see code).
    pa[7, 7, 3] = 1;
    // or read a value
    var x = pa[255];  // x=1

    // Go through all the elements and unpack the (x,y,z) values into an index:
    for (int row = 0; row < 8; row++)
    {
        for (int col = 0; col < 8; col++)
        {
            for (int wid = 0; wid < 4; wid++)
            {
                Debug.WriteLine($"[{row},{col},{wid}]=[{pa.Index(row, col, wid)}]={pa[row,col,wid]}");
            }
        }
    }

    // Recover the original array by using Enumerable.ToArray() extension
    int[] copy = pa.ToArray();
}

结果是:

[0,0,0]=[0]=0
[0,0,1]=[1]=0
[0,0,2]=[2]=0
[0,0,3]=[3]=0
[0,1,0]=[4]=0
[0,1,1]=[5]=0
...
[0,7,3]=[31]=0
[1,0,0]=[32]=0
[1,0,1]=[33]=0
...
[4,7,2]=[158]=0
[4,7,3]=[159]=0
[5,0,0]=[160]=0
[5,0,1]=[161]=0
...
[7,6,3]=[251]=0
[7,7,0]=[252]=0
[7,7,1]=[253]=0
[7,7,2]=[254]=0
[7,7,3]=[255]=1

答案 1 :(得分:0)

我认为你的嵌套for循环评估为O(n ^ 3)时间,所以它肯定会因较大的文件而变慢。

通过此修改,您可能会获得稍快但更难看的结果:

for (int row = 0; row++ < width;)
{
    for (int col = 0; col++ < height;)
    {
        for (int wid = 0; wid++ < hig;)
        {
            array3d[row, col, wid] = thisArray[sum++];
        }
    }
}

这与在福特Escort中拍打(蹩脚)涡轮增压器有很大不同。它会稍快一点,但绝不酷;)

请注意, 仍然 O(n ^ 3)。