我正在尝试使用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));
}
方法。还有别的吗?
答案 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)});