2012-08-11 61 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