2013-10-08 44 views
1

我有2D阿雷与此类似:最快的方式从二维数组中获取值

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 

获取所有“A”从该数组的长度为0.比从其他列获得腐蚀编码值。 这是超过6k值的大2d数组。但设计与上述完全相同。我曾尝试2种方法至今:

第1种方法:使用循环来遍历所有的值:

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));  

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

+0

我不能看看为什么第二个选项的所有开销会更快,甚至包括LINQ,如果你需要原始的性能,它永远不会是你想要去的地方 – usr

+0

这两个代码片段做不同的事情,令人困惑。 – usr

回答

1

正如“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]; 
    } 
} 

第一初始化新阵列(和然后设置“单元值)的主要性能升压

+0

F首先,如果D先出现,A出现后不起作用。我应该使用linq先获取行数吗? – NoviceMe

+0

可能是SkipWhile和TakeWhile的组合。我认为这将表现相当好。请注意,在这种情况下,第一个for循环的起始值必须是第一次出现的“A”。 –

+0

我需要同时获得A和D.所以上面的代码适用于获得A但不是D.我会尝试SkipWhile – NoviceMe

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(); 
+0

这将工作只有两列是正确的?但是我有超过10列? – NoviceMe

+0

@NoviceMe:那么你应该在你的问题中反映出这一点,那就是说,我将添加一个快速编辑 –

相关问题