如何更换一个序列的项目集合中,使用其他收藏品?(How to replace a sequence

2019-09-21 03:37发布

比方说,我有一个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

Answer 1:

OK,这里是根据你编辑的问题的答案。 经过充分测试,当然。

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


Answer 2:

如果你喜欢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);


Answer 3:

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.
    }
} 


Answer 4:

如果您需要支持一般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;
  }
}


Answer 5:

我认为这将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;
    }


文章来源: How to replace a sequence of items in a collection, using other collections?