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.

在更高级的场景中,我可能还需要使用多个参数替换源。认为fromArray并且toArray来自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
4

5 回答 5

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;
}
于 2012-08-11T10:18:31.620 回答
0

我认为它会正确工作,

    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;
    }
于 2012-08-11T08:52:01.593 回答
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);
于 2012-08-11T09:08:46.090 回答
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.
    }
} 
于 2012-08-11T09:09:40.127 回答
0

如果您需要支持 general IEnumerable<T>(而不是 arrays 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;
  }
}
于 2012-08-11T09:22:49.207 回答