10

String包含非常有用的方法 - String.Join(string, string[]).

它从一个数组创建一个字符串,用给定的符号分隔数组的每个元素。但一般 - 它不会在最后一个元素之后添加分隔符!我将它用于 ASP.NET 编码,以便用 " <br />" 或Environment.NewLine.

所以我想在asp:Table. 我可以使用什么方法IEnumerable<TableRow>来实现相同的功能?

4

9 回答 9

9

Linq 的等价物String.JoinAggregate

例如:

IEnumerable<string> strings;
string joinedString = strings.Aggregate((total,next) => total + ", " + next);

如果给定一个 TableRows 的 IE,代码将类似。

于 2010-04-18T13:21:55.340 回答
8

我写了一个扩展方法:

    public static IEnumerable<T> 
        Join<T>(this IEnumerable<T> src, Func<T> separatorFactory)
    {
        var srcArr = src.ToArray();
        for (int i = 0; i < srcArr.Length; i++)
        {
            yield return srcArr[i];
            if(i<srcArr.Length-1)
            {
                yield return separatorFactory();
            }
        }
    }

您可以按如下方式使用它:

tableRowList.Join(()=>new TableRow())
于 2009-06-14T20:05:32.223 回答
8

在 .NET 3.5 中,您可以使用此扩展方法:

public static string Join<TItem>(this IEnumerable<TItem> enumerable, string separator)
{
   return string.Join(separator, enumerable.Select(x => x.ToString()).ToArray());
}

或在 .NET 4 中

public static string Join<TItem>(this IEnumerable<TItem> enumerable, string separator)
{
   return string.Join(separator, enumerable);
}

但是问题需要在每个元素之后有一个分隔符,包括这个(3.5版本)可以工作的最后一个元素: -

public static string AddDelimiterAfter<TItem>(this IEnumerable<TItem> enumerable, string delimiter)
{
   return string.Join("", enumerable.Select(x => x.ToString() + separator).ToArray());
}

您也可以使用 .Aggregate 来执行此操作而无需扩展方法

于 2010-04-18T06:07:47.420 回答
1

没有内置的方法可以做到这一点,你应该自己动手。

于 2009-06-14T19:34:01.130 回答
1

如果我找不到适合我需要的方法,我会创建自己的方法。扩展方法非常好,因为它们可以让你扩展类似的东西。对 asp:table 不太了解,但这里至少有一个扩展方法,您可以调整到任何内容:p

public static class TableRowExtensions
{
    public string JoinRows(this IEnumerable<TableRow> rows, string separator)
    {
        // do what you gotta do
    }
}
于 2009-06-14T20:04:45.843 回答
1

您正在寻找的是一个Intersperse功能。有关此类函数的 LINQ 实现,请参阅此问题


顺便说一句,另一个可能的类似物String.JoinIntercalate函数,这实际上是我正在寻找的:

public static IEnumerable<T> Intercalate<T>(this IEnumerable<IEnumerable<T>> source,
                                            IEnumerable<T> separator) {
    if (source == null) throw new ArgumentNullException("source");
    if (separator == null) throw new ArgumentNullException("separator");
    return source.Intersperse(separator)
        .Aggregate(Enumerable.Empty<T>(), Enumerable.Concat);
}
于 2010-11-02T20:09:49.540 回答
1

我发现我经常使用这种扩展方法。

运气好的话,它可能会被合并到 C#中。

public static class Extensions
{
    public static string ToString(this IEnumerable<string> list, string separator)
    {
        string result = string.Join(separator, list);
        return result;
    }
}

用法:

var people = new[]
{
    new { Firstname = "Bruce", Surname = "Bogtrotter" },
    new { Firstname = "Terry", Surname = "Fields" },
    new { Firstname = "Barry", Surname = "Wordsworth"}
};

var guestList = people
                    .OrderBy(p => p.Firstname)
                    .ThenBy(p => p.Surname)
                    .Select(p => $"{p.Firstname} {p.Surname}")
                    .ToString(Environment.NewLine);
于 2019-04-17T08:32:05.277 回答
0

如果你要经常做这种事情,那么构建你自己的扩展方法来做这件事是值得的。下面的实现允许您执行相当于string.Join(", ", arrayOfStrings)arrayOfStrings 可以是 的地方IEnumerable<T>,并且分隔符可以是任何对象。它允许您执行以下操作:

var names = new [] { "Fred", "Barney", "Wilma", "Betty" };
var list = names
    .Where(n => n.Contains("e"))
    .Join(", ");

我喜欢这个的两点是:

  1. 它在 LINQ 上下文中非常易读。
  2. 它相当有效,因为它使用 StringBuilder 并避免对枚举进行两次评估。
public static string Join<TItem,TSep>(
    this IEnumerable<TItem> enuml,
    TSep                    separator)
{
    if (null == enuml) return string.Empty;

    var sb = new StringBuilder();

    using (var enumr = enuml.GetEnumerator())
    {
        if (null != enumr && enumr.MoveNext())
        {
            sb.Append(enumr.Current);
            while (enumr.MoveNext())
            {
                sb.Append(separator).Append(enumr.Current);
            }
        }
    }

    return sb.ToString();
}
于 2010-04-17T13:51:00.003 回答
0

我发现这篇文章正在寻找同样的东西,但对答案非常不满意(大多数似乎是关于加入字符串 [?],并且接受的答案似乎很冗长)。所以我最终只是想出了一些其他的方法来做到这一点。

我喜欢的方式是这样的:

public static IEnumerable<T> AfterEach <T> (this IEnumerable<T> source, T delimiter) =>
    source.SelectMany((item) => Enumerable.Empty<T>().Append(item).Append(delimiter));

或者,或者:

public static IEnumerable<T> AfterEach <T> (this IEnumerable<T> source, T delimiter) =>
    source.SelectMany((item) => new T[] { item, delimiter });

它们都是等价的:对于每个item,创建一个新序列{ item, delimiter },并使用SelectMany将它们连接在一起。

另一种方法,它不是单行但可能更容易阅读并且非常简单:

public static IEnumerable<T> AfterEach <T> (this IEnumerable<T> source, T delimiter) {
    foreach (T item in source) {
        yield return item;
        yield return delimiter;
    }
}

如果您希望末尾有额外的定界符,则方法类似,除了您连接{ delimiter, item }序列,然后Skip是开头的额外定界符(这比在末尾跳过一个更有效)。

public static IEnumerable<T> Delimit <T> (this IEnumerable<T> source, T delimiter) =>
    source.SelectMany((item) => Enumerable.Empty<T>().Append(delimiter).Append(item)).Skip(1);

public static IEnumerable<T> Delimit <T> (this IEnumerable<T> source, T delimiter) =>
    source.SelectMany((item) => new T[] { delimiter, item }).Skip(1);

收益率方法是这样的(同样,两个类似的选项,只取决于你的感觉):

public static IEnumerable<T> Delimit <T> (this IEnumerable<T> source, T delimiter) {
    foreach (T item in source.Take(1)) // protects agains empty source
        yield return item;
    foreach (T item in source.Skip(1)) {
        yield return delimiter;
        yield return item;
    }
}

public static IEnumerable<T> Delimit <T> (this IEnumerable<T> source, T delimiter) {
    static IEnumerable<U> Helper<U> (IEnumerable<U> source, U delimiter) {
        foreach (U item in source) {
            yield return delimiter;
            yield return item;
        }
    }
    return Helper(source, delimiter).Skip(1);
}

这里有一些可运行的示例和测试代码(for Delimit,not AfterEach)。那里也有一个我认为不值得在这里写的实现。它可以以类似的方式进行调整。AggregateAfterEach

于 2021-06-11T20:53:19.027 回答