30

我想使用Enumerable.Aggregate(...)方法连接由分号分隔的字符串列表。相当容易,不是吗?

考虑到以下几点:

  • private const string LISTSEPARATOR = "; ";
  • 专辑。OrderedTracksList<TrackDetails>
  • TrackDetailsDiscNumber Int16?财产

如果Distinct()返回的序列为空(因为Aggregate()方法不适用于空序列),则以下语句将引发异常:

    txtDiscNumber.Text = album.OrderedTracks
        .Where(a => a.DiscNumber.HasValue)
        .Select(a => a.DiscNumber.Value.ToString())
        .Distinct()
        .Aggregate((i, j) => i + LISTSEPARATOR + j);

我正在使用的解决方法:

    List<string> DiscNumbers = 
        album.OrderedTracks
            .Where(a => a.DiscNumber.HasValue)
            .Select(a => a.DiscNumber.Value.ToString())
            .Distinct()
            .ToList();

    if (!DiscNumbers.Any())
        txtDiscNumber.Text = null;
    else
        txtDiscNumber.Text = 
            DiscNumbers.Aggregate((i, j) => i + LISTSEPARATOR + j);

有没有更好的解决方案?是否可以在单个 LINQ 语句中执行此操作?

提前致谢。

4

5 回答 5

49

要连接字符串列表,请使用string.Join方法。

Aggregate函数不适用于空集合。它需要一个二进制累积函数,并且它需要集合中的一个项目作为种子值传递给二进制函数。

但是,有一个重载Aggregate

public static TResult Aggregate<TSource, TAccumulate, TResult>(
    this IEnumerable<TSource> source,
    TAccumulate seed,
    Func<TAccumulate, TSource, TAccumulate> func,
    Func<TAccumulate, TResult> resultSelector
)

此重载允许您指定种子值。如果指定了种子值,如果集合为空,它也将用作结果。

编辑:如果你真的想使用Aggregate,你可以这样做:

sequence.Aggregate(string.Empty, (x, y) => x == string.Empty ? y : x + Separator + y)

或者这样使用StringBuilder

sequence.Aggregate(new StringBuilder(), (sb, x) => (sb.Length == 0 ? sb : sb.Append(Separator)).Append(x)).ToString()
于 2013-02-15T14:46:23.507 回答
11

我想您可能会发现以下辅助扩展方法很有用。

public static TOut Pipe<TIn, TOut>(this TIn _this, Func<TIn, TOut> func)
{
    return func(_this);
}

它允许您以下列方式表达您的查询。

txtDiscNumber.Text = album.OrderedTracks
    .Where(a => a.DiscNumber.HasValue)
    .Select(a => a.DiscNumber.Value.ToString())
    .Distinct()
    .Pipe(items => string.Join(LISTSEPARATOR, items));

这仍然是“从上到下”,这极大地提高了可读性。

于 2013-02-15T21:17:59.410 回答
7

像这样使用String.Join

 txtDiscNumber.Text = String.Join(LISTSEPARATOR,
      album.OrderedTracks
                  .Where(a => a.DiscNumber.HasValue)
                  .Select(a => a.DiscNumber.Value.ToString())
                  .Distinct());
于 2013-02-15T14:46:58.417 回答
4

您可以使用

.Aggregate(string.Empty, (i, j) => i + LISTSEPARATOR + j);

初始值适用于空集合

于 2019-02-20T15:45:12.540 回答
0

出于调试目的,经常使用这样的方法,提出了两种扩展方法:

public static string Concatenate<T, U>(this IEnumerable<T> source, Func<T, U> selector, string separator = ", ")
{
    if (source == null)
    {
        return string.Empty;
    }

    return source
        .Select(selector)
        .Concatenate(separator);
}

public static string Concatenate<T>(this IEnumerable<T> source, string separator = ", ")
{
    if (source == null)
    {
        return string.Empty;
    }

    StringBuilder sb = new StringBuilder();
    bool firstPass = true;
    foreach (string item in source.Distinct().Select(x => x.ToString()))
    {
        if (firstPass)
        {
            firstPass = false;
        }
        else
        {
            sb.Append(separator);
        }

        sb.Append(item);
    }

    return sb.ToString();
}

像这样使用:

string myLine = myCol.Concatenate(x => x.TheProperty);
于 2013-02-15T15:42:10.957 回答