比方说,我有一个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
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;
}
如果你喜欢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);
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.
}
}
如果您需要支持一般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;
}
}
我认为这将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?