使用LINQ将元素追加到集合中

时间:2011-11-18 09:42:42

标签: c# linq functional-programming

我正在尝试使用C#中的函数方法处理一些列表。

我的想法是我有一个Tuple<T,double>的集合,我想要更改某个元素Item 2的{​​{1}}。

这样做的功能方法,因为数据是不可变的,就是获取列表,过滤元素与要更改的元素不同的所有元素,并使用新值附加新元组。

我的问题是我不知道如何在最后添加元素。我想这样做:

T

但是没有public List<Tuple<T,double>> Replace(List<Tuple<T,double>> collection, T term,double value) { return collection.Where(x=>!x.Item1.Equals(term)).Append(Tuple.Create(term,value)); } 方法。还有别的吗?

7 个答案:

答案 0 :(得分:7)

我相信您正在寻找Concat运营商。

它将两个IEnumerable<T>连接在一起,因此您可以创建一个包含单个项目的项目。

public List<Tuple<T,double>> Replace(List<Tuple<T,double>> collection, T term,double value)
{
   var newItem = new List<Tuple<T,double>>();
   newItem.Add(new Tuple<T,double>(term,value));
   return collection.Where(x=>!x.Item1.Equals(term)).Concat(newItem).ToList();
}

答案 1 :(得分:3)

LINQ不适用于变异。 功能编程避免变异。

因此:

public IEnumerable<Tuple<T,double>> Extend(IEnumerable<Tuple<T,double>> collection, 
   T term,double value)
{
   foreach (var x in collection.Where(x=>!x.Item1.Equals(term)))
   {
     yield return x;
   }
   yield return Tuple.Create(term,value);
}

答案 2 :(得分:2)

如果您愿意使用其他套餐,请查看Nuget上提供的MoreLinq。这为Concat - 函数:

提供了新的重载
public static IEnumerable<T> Concat<T>(this IEnumerable<T> head, T tail);

此功能完全符合要求,例如:你可以做到

var myEnumerable = Enumerable.Range(10, 3); // Enumerable of values 10, 11, 12
var newEnumerable = myEnumerable.Concat(3); // Enumerable of values 10, 11, 12, 3

而且,如果您喜欢LINQ,您可能也会喜欢很多其他新功能!

此外,在关于MoreLinq Github页面的讨论中,pointed out为函数

public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> source, TSource element);

具有不同的名称,但.NET Core中提供了相同的功能,因此我们可能会在将来看到它用于C#。

答案 3 :(得分:2)

.NET 4.7.1似乎添加了Append LINQ运算符,这正是您想要的。与Concat不同,它只需要一个值。

顺便说一句,如果你声明一个泛型方法,你应该在其名称后面加上类型参数:

public List<Tuple<T, double>> Replace<T>(List<Tuple<T, double>> collection, T term, double value)                                     
{
    return collection.Where(x => !x.Item1.Equals(term))
                     .Append(Tuple.Create(term, value))
                     .ToList();
}

答案 4 :(得分:1)

这应该做你想要的(尽管它在内部使用变异,从调用者的角度来看,感觉功能):

public List<Tuple<T, double>> Replace(List<Tuple<T, double>> collection, T term, double value) {
  var result = collection.Where(x => !x.Item1.Equals(term)).ToList();
  result.Add(Tuple.Create(term, value));
  return result;
}

另一种方法是在LINQ中使用"map"select):

public List<Tuple<T, double>> Replace(List<Tuple<T, double>> collection, T term, double value) {
  return collection.Select(x => 
    Tuple.Create(
      x.Item1, 
      x.Item1.Equals(term) ? value : x.Item2)).ToList();
}

但它可能会给你不同于你原来意图的结果。虽然,对我来说,当我看到一个名为Replace的方法时,我就会这样想,就是替换它。

<强>更新

你也可以像这样创建你想要的东西:

public List<Tuple<T, double>> Replace(List<Tuple<T, double>> collection, T term, double value) {
  return collection.
    Where(x => !x.Item1.Equals(term)).
    Append(Tuple.Create(term, value)).
    ToList();
}

使用Concat,如Oded所述:

public static class EnumerableEx {
  public static IEnumerable<T> Append<T>(this IEnumerable<T> source, T item) {
    return source.Concat(new T[] { item });
  }
}

答案 5 :(得分:1)

一种方法是使用.Concat(),但是你需要有一个可枚举项而不是一个项作为第二个参数。使用单个元素创建数组确实有效,但编写起来很简洁。

最好编写自定义扩展方法来执行此操作。

一种方法是创建一个新的List<T>并添加第一个列表中的项目,然后添加第二个列表中的项目。但是,最好使用yield - 关键字,因此您不需要创建列表,并且将以惰性方式评估枚举:

public static class EnumerableExtensions
{
    public static IEnumerable<T> Concat<T>(this IEnumerable<T> list, T item)
    {
        foreach (var element in list)
        {
            yield return element;
        }
        yield return item;
    }
}

答案 6 :(得分:0)

我能找到的最接近的答案来自this post并且是:

return collection.Where(x=>!x.Item1.Equals(term)).Concat(new[]{Tuple.Create(term,value)});