LINQ聚合对列表最后一个元素的特殊关注

本文关键字:元素 最后一个 列表 LINQ | 更新日期: 2023-09-27 18:04:51

我想为集合中的最后一个元素传递一个不同的函数给Aggregate

它的用法是:

List<string> listString = new List{"1", "2", "3"};
string joined = listString.Aggregate(new StringBuilder(), 
                                    (sb,s) => sb.Append(s).Append(", "), 
                                    (sb,s) => sb.Append(s)).ToString();
//joined => "1, 2, 3"

如果没有其他自定义实现,将是什么?

注:我想这样做w/可组合函数迭代一次通过集合。换句话说,我不想用String.Join

LINQ聚合对列表最后一个元素的特殊关注

包裹Select

Aggregate不允许这样做。

您可以携带前一个元素,并在Aggregate之后进行最终处理。此外,我认为你最好的选择是编写自定义方法,对最后一个(也可能是第一个)元素进行自定义处理。

最后一项的Aggregate的一些近似代码(不是处理大多数特殊情况,如空/短列表):

var firstLast = seq.Aggregate(
  Tuple.Create(new StringBuilder(), default(string)),
  (sum, cur) => 
     {
       if (sum.Item2 != null)
       {
            sum.Item1.Append(",");
            sum.Item1.Append(sum.Item2);
       }
       return Tuple.Create(sum.Item1, cur);
     });
 firstLast.Item1.Append(SpecialProcessingForLast(sum.Item2));
 return firstLast.Item1.ToString();  

Aggregate与"last"的特殊情况。示例已准备好复制/粘贴到LinqPad/console应用程序,在制作扩展功能时取消注释"this"。Main显示聚合数组,对除最后一个元素外的所有元素求和,最后一个元素从result中减去:

void Main()
{
   Console.WriteLine(AggregateWithLast(new[] {1,1,1,-3}, 0, (s,c)=>s+c, (s,c)=>s-c));
   Console.WriteLine(AggregateWithLast(new[] {1,1,1,+3}, 0, (s,c)=>s+c, (s,c)=>s-c));
}
public static TAccumulate AggregateWithLast<TSource, TAccumulate>(
    /*this */ IEnumerable<TSource> source, 
    TAccumulate seed,
    Func<TAccumulate, TSource, TAccumulate> funcAll,
    Func<TAccumulate, TSource, TAccumulate> funcLast)
{
  using (IEnumerator<TSource> sourceIterator = source.GetEnumerator())
  {
    if (!sourceIterator.MoveNext())
    {
      return seed;
    }
    TSource last = sourceIterator.Current;
    TAccumulate total = seed;
    while (sourceIterator.MoveNext())
    {
      total = funcAll(total, last);
      last = sourceIterator.Current;
    }
    return funcLast(total, last);
  }
}

注意:如果你只需要String.Join而不是。net 4.0+中的一个需要IEnumerable<T> -所以它只会迭代序列一次而不需要ToList/ToArray

对于您的特定示例,另一种方法是跳过第一个元素的逗号,并将其添加到尾部元素,如下所示:

List<string> listString = new() { "1", "2", "3" };
string joined = listString
    .Select((value, index) => (value, index))
    .Aggregate(new StringBuilder(), (sb, s) =>
        s.index == 0
            ? sb.Append(s.value)
            : sb.Append(", ").Append(s.value))
    .ToString();

我知道这并不能解决标题中的问题,但对于大多数人来说,"用一些中缀"来连接事物"。问题,这个很好用。也就是说,string.Join不是解决方案。