2013-10-08 43 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:那麼你應該在你的問題中反映出這一點,那就是說,我將添加一個快速編輯 –

相關問題