1

我有与此类似的二维数组:

string[,] arr = { 
                    { "A", "A", "A", "A", "A", "A", "A", "D", "D", "D", "D", "D", "D", "D", "D" }, 
                    { "1", "1", "1", "1", "1", "1", "1", "0", "0", "0", "0", "0", "0", "0", "0" },
                    { "2", "2", "2", "2", "2", "2", "2", "00", "00", "00", "00", "00", "00", "00", "00" }  
                };

我试图从上面的数组中得到以下结果:

A 1 2
A 1 2
A 1 2
A 1 2
A 1 2
A 1 2

从长度为 0 的数组中获取所有“A”。而不是从其他列中获取它的腐蚀值。这是具有超过 6k 个值的大型二维数组。但设计与上述完全相同。到目前为止,我尝试了两种方法:

第一种方法:使用for循环遍历所有值:

var myList = new List<string>();
var arrLength = arr.GetLength(1)-1;
for (var i = 0; i < arrLength; i++)
{
    if (arr[0,i].Equals("A"))
        myList.Add(arr[0, i]);
    else
        continue;
    }
}

第二种方法:创建列表而不是遍历所有值:

var dataList = new List<string>();
var list = Enumerable.Range(0, arr.GetLength(1))
                     .Select(i => arr[0, i])
                     .ToList();

var index = Enumerable.Range(0, arr.GetLength(1))
                      .Where(index => arr[0, index].Contains("A"))
                      .ToArray();
var sI = index[0];
var eI = index[index.Length - 1];
myList.AddRange(list.GetRange(sI, eI - sI));      

他们似乎都很慢,效率不够。有没有更好的方法来做到这一点?

4

2 回答 2

2

我喜欢以我的代码最终成为自我记录的方式来处理这些类型的算法。通常,用你的代码描述算法,而不是用代码特性来膨胀它,往往会产生很好的结果。

var matchingValues =
    from index in Enumerable.Range(0, arr.GetLength(1))
    where arr[0, index] == "A"
    select Tuple.Create(arr[1, index], arr[2, index]);

对应于:

// find the tuples produced by
//     mapping along one length of an array with an index
//     filtering those items whose 0th item on the indexed dimension is A"
//     reducing index into the non-0th elements on the indexed dimension

只要您保持简单的“映射、过滤、减少”范式并避免引入副作用,这应该可以很好地并行化。

编辑:

为了返回与“A”关联的列的任意集合,您可以:

var targetValues = new int[] { 1, 2, 4, 10 };
var matchingValues =
    from index in Enumerable.Range(0, arr.GetLength(1))
    where arr[0, index] == "A"
    select targetValues.Select(x => arr[x, index]).ToArray();

要使其成为一个完整的集合,只需使用:

var targetValues = Enumerable.Range(1, arr.GetLength(0) - 1).ToArray();
于 2013-10-08T22:23:23.690 回答
1

As "usr" said: back to the basics if you want raw performance. Also taking into account that the "A" values can start at an index > 0:

var startRow = -1; // "row" in the new array.
var endRow = -1;

var match = "D";

for (int i = 0; i < arr.GetLength(1); i++)
{
    if (startRow == -1 && arr[0,i] == match) startRow = i;
    if (startRow > -1 && arr[0,i] == match) endRow = i + 1;
}

var columns = arr.GetLength(0);
var transp = new String[endRow - startRow,columns]; // transposed array

for (int i = startRow; i < endRow; i++)
{
    for (int j = 0; j < columns; j++)
    {
        transp[i - startRow,j] = arr[j,i];
    }
}

Initializing the new array first (and then setting the "cell values) is the main performance boost.

于 2013-10-08T23:07:45.093 回答