LINQ聚合列表的最后一个元素的特别注意

时间:2014-05-22 18:08:15

标签: c# linq

我想为集合中的最后一个元素传递一个不同的函数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"

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

P.S。我想做这个w /可组合函数迭代一次通过集合。换句话说,我不想在Select

中包含String.Join

1 个答案:

答案 0 :(得分:2)

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以及“最后”的特殊情况。样本已准备好复制/粘贴到LinqPad / console应用程序,在进行扩展功能时取消注释“this”。 Main显示聚合数组,除了最后一个元素之外的所有元素,从结果中减去最后一个:

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