2012-02-01 33 views
0

給定兩個數組,我需要根據arrayA中的範圍(實際值)所在的位置從arrayB中提取值。如何使用上限和下限從數組中提取值?

Index  0 1 2 3 4 5 6 7 8  9 10 11 12 
------------------------------------------------------------- 
ArrayA = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6} 
ArrayB = {1, 0.2, 3, 4, 5, 6,5.5, 8, 9,11.1, 11, 12, 3} 

考慮下列範圍內,我需要提取以下結果

RangeToExtract* IndexInArrayA Expected Values To Extract 
-------------- ------------- -------------------------- 
0 -> 1   [0,2]   1,0.2,3 
1 -> 3   [3,6]   4,5,6,5.5 
3 -> 5   [7,10]   5.5,8,9,11.1,11 
1 -> 5   [3,10]   4,5,6,5.5,8,9,11.1,11 
3 -> 10   [7,12]   8,9,11.1,11,12,3 

* Refers to the actual values in ArrayA 

注:鑑於RangeToExtract (0->1),確定在ArrayA指標,其中這些值,其結果是(0->1)映射到[0,2](數值1在ArrayA中的位置2處)

我只計算出以下特殊情況存在(不確定是否有更多)

當上限不ArrayA存在
  1. 下限爲等於零和

進一步信息:

  • 兩個陣列將具有相同的尺寸
  • ArrayA將始終進行排序

代碼:

private double[] GetRange(double lower, double upper) 
{ 
    var myList = new double[ArrayA.Length]; 
    var lowerIndex = Array.IndexOf(ArrayA, lower); 
    var upperIndex = Array.IndexOf(ArrayA, upper); 

    // special case 1 
    if (lowerIndex != 0) 
    { 
     lowerIndex = lowerIndex + 1; 
    } 

    // special case 2 
    if (upperIndex == -1) 
    { 
     upperIndex = ArrayA.Length-1; 
    } 

    for (int i = lowerIndex; i <= upperIndex; i++) 
    { 
     myList[i] = ArrayB[i]; 
    } 
    return myList; 
} 

鑑於上面的代碼,所有的特殊情況已被考慮到?有沒有更好的方式來編寫上面的代碼?

+0

您還應該確保ArrayA中的值是唯一的IMO。 – Marco 2012-02-01 07:35:34

+0

@Marco - 值將永遠是唯一的 – Ahmad 2012-02-01 07:36:36

+0

ArrayA是否會被排序? ArrayB中的值是否總是1-N? – 2012-02-01 07:39:44

回答

0

Yap!有一個更好的方法,可愛的LINQ來。我以兩種形式放在這裏。首先看起來很複雜,但不是全部!相信我;)

第一一步,你必須拿出那些A'indexes它們的值落入你的範圍(我稱之爲min...max),根據您的例子中,我得到了你的範圍是從封閉下邊界關閉關於上邊,我的意思是當你提到3 -> 5其實它是[3, 5)!它不包含5.無論如何,這不是問題。

這可以通過以下LINQ

int[] selectedIndexes = a.Select((value, index) => 
    new { Value = value, Index = index }). 
     Where(aToken => aToken.Value > min && aToken.Value <= max). 
    Select(t => t.Index).ToArray<int>(); 

第一選擇來完成,產生的[Value, Index]對的集合,所述第一個是數組元素和第二個距離的元素的索引陣列。我認爲這是你問題的主要技巧。所以它爲您提供了使用與通常值相同的索引的能力。

最後在秒選擇我只是將整個索引包裝到一個整數數組中。因此,在此之後,您的整個指標都會落在指定範圍內。

現在第二步

當你有這些索引,您必須選擇從A.同樣的事情應該在B.要做的選擇指標下內所有元素它意味着我們再次選擇B元素到集合[價值指數]對,然後我們選擇那些傢伙從A.這是可以做到如下的選擇的指標內有他們的索引:

double[] selectedValues = b.Select((item, index) => 
    new { Item = item, Index = index }). 
     Where(bToken => selectedIndexes.Contains(bToken.Index)). 
    Select(d => d.Item).ToArray<double>(); 

好了,首先選擇是一個我在第一部分中談到了它,然後看看where部分檢查哪個是B的一個元素的索引是否存在於selectedIndexes(來自A)!

最後我都包代碼轉換成一個如下圖所示:

double[] answers = b.Select((item, index) => 
    new { Item = item, Index = index }). 
     Where(bTokent => 
     a.Select((value, index) => 
      new { Value = value, Index = index }). 
       Where(aToken => aToken.Value > min && aToken.Value <= max). 
      Select(t => t.Index). 
     Contains(bTokent.Index)).Select(d => d.Item).ToArray<double>(); 

購買啤酒對我來說,如果它是有用的:)

+0

你對範圍的陳述是混淆的。它在底部是**打開**,在頂部是關閉的,所以它實際上是'(3,5)',而*是*包含5。 – 2012-02-01 08:24:06

0

我不知道你是否仍然有興趣,但我看到了這一個,我喜歡挑戰。如果你使用.NET 4.0(具有Enumberable.Zip方法)有一個非常簡潔的方式來做到這一點(因爲下futher信息條件):

arrayA.Zip(arrayB, (a,b) => new {a,b}) 
    .Where(x => x.a > lower && x.a < upper) 
    .Select (x => x.b) 

您可能需要使用>=<=到進行範圍比較包容性。