2012-08-11 81 views
2

比方說,我有一個int數組:如何使用其他集合來替換集合中的一系列項目?

var source = new int[] { 1, 2, 3, 4, 5 }; 

我想用這些陣列來替代它的一部分:

var fromArray = new int[] { 1, 2 }; 
var toArray = new int[] { 11, 12 }; 

我需要製作使用上述陣列的輸出是:11, 12, 3, 4, 5

在更高級的場景,我可能還需要更換使用多個參數源。認爲fromArraytoArray是從Dictionary<int[], int[]>來:

IEnumerable<T> Replace(IEnumerable<T> source, 
         IDictionary<IEnumerable<T>, IEnumerable<T>> values) 
{ 
    // "values" parameter holds the pairs that I want to replace. 
    // "source" can be `IList<T>` instead of `IEnumerable<T> if an indexer 
    // is needed but I prefer `IEnumerable<T>`. 
} 

我怎樣才能做到這一點?

編輯:項目的的順序很重要。認爲它像String.Replace;如果fromArray的全部內容不存在source(如果源只有1而不是2,例如)的方法不應試圖取代它。舉個例子:

var source = new int[] { 1, 2, 3, 4, 5, 6 }; 
var dict = new Dictionary<int[], int[]>(); 

// Should work, since 1 and 2 are consecutive in the source. 
dict[new int[] { 1, 2 }] = new int[] { 11, 12 }; 

// There is no sequence that consists of 4 and 6, so the method should ignore it. 
dict[new int[] { 4, 6 }] = new int[] { 13, 14 }; 

// Should work. 
dict[new int[] { 5, 6 }] = new int[] { 15, 16 }; 

Replace(source, dict); // Output should be: 11, 12, 3, 4, 15, 16 
+0

PS,你的簽名是不完全正確,變化值具有的IEnumerable的鍵 2012-08-11 09:10:15

+0

@MAfifi - 我不明白,爲什麼呢? – 2012-08-11 09:13:11

+0

您將嘗試使用類型T對數組進行索引。這不起作用,因爲索引器總是期望它是一個整數。看我下面的例子。 – 2012-08-11 09:25:01

回答

1

好的,這裏有一個基於你編輯的問題的答案。當然,完全沒有經過測試。

static IEnumerable<T> Replace<T>(IEnumerable<T> source, IDictionary<IEnumerable<T>, IEnumerable<T>> values) 
{ 
    foreach (var kvp in values) 
    source = ReplaceOne(source, kvp.Key, kvp.Value); 
    return source; 
} 

static IEnumerable<T> ReplaceOne<T>(IEnumerable<T> source, IEnumerable<T> fromSeq, IEnumerable<T> toSeq) 
{ 
    var sArr = source.ToArray(); 

    int replLength = fromSeq.Count(); 
    if (replLength != toSeq.Count()) 
    throw new NotSupportedException(); 

    for (int idx = 0; idx <= sArr.Length - replLength; idx++) 
    { 
    var testSeq = Enumerable.Range(idx, replLength).Select(i => sArr[i]); 
    if (testSeq.SequenceEqual(fromSeq)) 
    { 
     Array.Copy(toSeq.ToArray(), 0, sArr, idx, replLength); 
     idx += replLength - 1; 
    } 
    } 

    return sArr; 
} 
+0

看起來不錯,將源代碼轉換爲數組並且每次計算值都可能達到性能,但正如我所說的,如果需要計數和索引器,則可以使用IList 而不是IEnumerable 。我會盡快嘗試。 – 2012-08-11 10:21:18

+0

如果'replLength'可能爲零,則應該將'for'循環放入'if(replLength!= 0)'塊中。 – 2012-08-11 10:26:05

+0

另請注意,您可能無法知道「foreach」以什麼順序通過「IDictionary <,>」。如果源是'a,b,c',一個替換是'a→m',另一個替換是'c→a'(或'a→k'),那麼替換的順序很重要。你不能用一個標準的'字典<,>'控制這個順序。 – 2012-08-11 10:33:59

0

我認爲這將corretly工作,

void Replace<T>(ref T[] source, IDictionary<T[], T[]> values) 
    { 
     int start = 0; 
     int index = -1; 
     foreach (var item in values) 
     { 
      start = 0; 

      while ((index = IndexOfSequence<T>(source, item.Key, start)) >= 0) 
      { 
       for (int i = index; i < index + item.Key.Length; i++) 
       { 
        source[i] = item.Value[i - index]; 
       } 

       start = index + item.Key.Length + 1; 
      } 
     } 
    } 

    public int IndexOfSequence<T>(T[] source, T[] sequence, int start) 
    { 
     int j = -1; 

     if (sequence.Length == 0) 
      return j; 

     for (int i = start; i < source.Length; i++) 
     { 
      if (source[i].Equals(sequence[0]) && source.Length >= i + sequence.Length) 
      { 
       for (j = i + 1; j < i + sequence.Length; j++) 
       { 
        if (!source[j].Equals(sequence[j - i])) 
         break; 
       } 

       if (j - i == sequence.Length) 
        return i; 
      } 
     } 

     return -1; 
    } 
+0

這很好。如果'source'有重複,這個解決方案只替換每個'i'的'source'中的一個元素。 – 2012-08-11 09:05:29

0

如果你愛LINQ :)

var replaced = source.Zip(fromArray.Zip(toArray, (x, y) => new {From = x, To = y}), 
             (x, y) => new {Src = x, Dest = y}). 
       Select(x => x.Src == x.Dest.From ? x.Dest.To : x.Src); 
+0

你試過編譯你的代碼嗎? – 2012-08-11 09:13:23

+0

@ L.B,剛試過。對不起,要修復 – 2kay 2012-08-11 09:14:24

0
IEnumerable<T> Replace(IEnumerable<T> source, 
    IDictionary<IEnumerable<int>, IEnumerable<T>> values) 
{ 
    // "values" parameter holds the pairs that I want to replace. 
    // "source" can be `IList<T>` instead of `IEnumerable<T> if an indexer 
    // is needed but I prefer `IEnumerable<T>`. 

    IList<T> sourceAsList = source as IList<T>; 
    if (sourceAsList == null) 
    { 
     sourceAsList = source.ToList(); 
    } 

    foreach (var kvp in values) 
    { 
     // repeat same thing as above. 
    } 
} 
0

如果您需要支持通用IEnumerable<T>(而不是陣列T[]),也許是這樣的:

IEnumerable<T> Replace<T>(IEnumerable<T> source, IEnumerable<T> fromSeq, IEnumerable<T> toSeq) 
{ 
    var dict = fromSeq.Zip(toSeq, (fr, to) => new { Fr = fr, To = to }) 
    .ToDictionary(a => a.Fr, a => a.To); 

    foreach (var s in source) 
    { 
    T replace; 
    if (dict.TryGetValue(s, out replace)) 
     yield return replace; 
    else 
     yield return s; 
    } 
} 
+0

嗯,沒有看到你對'source'連續元素的編輯。 – 2012-08-11 09:27:44

相關問題