Linq 从二维数组中获取值的最快方法

Linq 从二维数组中获取值的最快方法,linq,c#-3.0,Linq,C# 3.0,我有一个类似的例子: 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" }, {

我有一个类似的例子:

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”。然后从其他列中获取它的腐蚀值。 这是一个大的2d数组,具有超过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));      
var myList=new List();
var arrLength=arr.GetLength(1)-1;
对于(变量i=0;i
第二种方法:创建列表,然后遍历所有值:

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));      
var dataList=newlist();
变量列表=可枚举的范围(0,arr.GetLength(1))
.选择(i=>arr[0,i])
.ToList();
var索引=可枚举的范围(0,arr.GetLength(1))
.Where(index=>arr[0,index]。包含(“A”))
.ToArray();
var sI=指数[0];
var eI=指数[index.Length-1];
myList.AddRange(list.GetRange(sI,eI-sI));

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

我喜欢以一种我的代码可以自我记录的方式来处理这类算法。通常,用代码描述算法,而不是用代码特性膨胀算法,往往会产生相当好的结果

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
只要您坚持简单的“映射、过滤、减少”范式,并且避免引入副作用,这应该可以非常好地并行化

编辑:

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));      
为了返回与“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();
正如“usr”所说:如果您想要原始性能,请回到基础。还考虑到“A”值可以从索引>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];
    }
}
var startRow=-1;//新数组中的“行”。
var endRow=-1;
var match=“D”;
for(int i=0;i-1&&arr[0,i]==match)endRow=i+1;
}
var columns=arr.GetLength(0);
var transp=新字符串[endRow-startRow,columns];//转置阵列
对于(int i=startRow;i

首先初始化新数组(然后设置“单元格值”)是主要的性能提升。

我看不出第二个选项及其所有开销会更快的原因。它甚至涉及LINQ,如果您需要原始性能,它从来都不是您想要去的地方。而且这两个代码片段做不同的事情。令人困惑。这只适用于两列,对吗?但我有超过10列?@Nearome:然后你应该在你的问题中反映这一点。也就是说,我将添加一个快速编辑。如果D在前,a在后,First while不起作用。我应该使用linq首先获取行数吗?可能是SkipWhile和TakeWhile的组合。我认为这将相当好地执行。请注意,在这种情况下,First for循环的起始值必须是b第一次出现“A”。我需要同时得到A和D。因此,上面的代码可以得到A,但不能得到D。我将尝试SkipWhile这就是你的意思吗?var result=Enumerable.Range(0,arr.GetLength(1)).SkipWhile(I=>arr[0,I]。Contains(“A”)。TakeWhile(I=>arr[0,I]。Contains(“D”));而不是以行的形式获取结果的长度?有没有办法只获取第一列的长度?因为我们得到的是整个2d数组的长度,但我们只需要第一列的长度?我想这会使查询更快速,但我在谷歌上搜索了一下,什么也没找到。