首页 > 解决方案 > 使用 LINQ 替换 C# 中可枚举的一个元素

问题描述

我在使用 linq 方面很新,并且已经玩了几天了。我目前的问题是,我在这个可枚举中有一个可枚举和一个特定对象,应该用一个新实例替换它。

使用 for 循环,我会像这样实现它:

public IEnumerable<Foo> ReplaceFirst(IEnumerable<Foo> enumerable, Foo obj)
{
    Foo[] array = enumerable.ToArray();
    bool used = false;
    for (int i = 0; i < array.Length; i++) 
        if(array[i] == obj)
        {
            array[i] = new Foo();
            used = true;
            break;
        }

        if (used)
            return array;
        else
            throw new ArgumentException("obj not found in enumerable");
}

现在我正在寻找一个带有 linq 的实现。到目前为止我发现的是:

public IEnumerable<Foo> ReplaceFirst(IEnumerable<Foo> enumerable, Foo obj)
{
    return enumerable.Contains(obj) 
            ? locatedPieces.TakeWhile(current => current != obj)
                .Append(new Foo())
                .Concat(enumerable.SkipWhile(current => current != obj)
                    .Skip(1)) 
            : throw new ArgumentException("obj not found in enumerable");
}

但我不太确定这个实现是否有效,因为它必须至少迭代可枚举三次(在ContainsTakeWhileSkipWhile处)。

有没有更好的方法来用 linq 实现这个功能,或者我应该继续使用 for-loop 变体?

标签: c#linq

解决方案


我建议为此创建一个扩展方法,如下所示:

public static IEnumerable<T> Replace<T>(this IEnumerable<T> source, T oldVal, T newVal)
{
    return source.Select(e => EqualityComparer.Default.Equals(e, oldVal) ? newVal : e);
}

这将遍历源并返回源元素,除了那些 == oldValue 的元素。

这也使用延迟执行。仅当您开始枚举生成的 IEnumerable 时才会枚举源。因此,如果您在调用此新的 Replace 扩展后更改源序列,则生成的序列也将产生此更改。


推荐阅读