类String
包含非常有用的方法 - String.Join(string, string[])
。
它从数组创建一个字符串,用给定的符号分隔数组的每个元素。但一般 - 它不会在最后一个元素后添加分隔符!我将它用于ASP.NET编码,以便与“<br />
”或Environment.NewLine
分开。
所以我想在asp:Table
的每一行之后添加一个空行。我可以使用IEnumerable<TableRow>
的相同功能使用哪种方法?
答案 0 :(得分: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())
答案 1 :(得分:8)
Linq等同于String.Join
是Aggregate
例如:
IEnumerable<string> strings;
string joinedString = strings.Aggregate((total,next) => total + ", " + next);
如果给出TableRows的IE,代码将类似。
答案 2 :(得分:7)
在.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来执行此操作,而无需使用扩展方法。
答案 3 :(得分:1)
如果我找不到适合我需要的方法,我会创建自己的方法。扩展方法非常好,因为它们可以让你扩展这样的东西。不太了解asp:table,但这里至少有一个扩展方法,你可以调整到什么:p
public static class TableRowExtensions
{
public string JoinRows(this IEnumerable<TableRow> rows, string separator)
{
// do what you gotta do
}
}
答案 4 :(得分:1)
您正在寻找的是Intersperse
功能。对于此类函数的LINQ实现,请参阅this question。
顺便提一下,String.Join
的另一种可能模拟是Intercalate
函数,这实际上就是我想要的:
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);
}
答案 5 :(得分:1)
我发现我经常使用这种扩展方法。
如果运气好的话,可能是incorporated into 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);
答案 6 :(得分:0)
没有内置方法可以做到这一点,你应该自己动手。
答案 7 :(得分:0)
如果您经常要做这类事情,那么建立自己的扩展方法是值得的。下面的实现允许您执行相当于string.Join(", ", arrayOfStrings)
的数组,其中arrayOfStrings可以是IEnumerable<T>
,而分隔符可以是任何对象。它允许你做这样的事情:
var names = new [] { "Fred", "Barney", "Wilma", "Betty" };
var list = names
.Where(n => n.Contains("e"))
.Join(", ");
我喜欢这两件事:
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();
}
答案 8 :(得分: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);
yield 方法是这样的(同样,两个相似的选项,只取决于你的感受):
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);
}
有一些可运行的示例和测试代码(用于 Delimit
,而不是 AfterEach
)here。那里也有一个带有 Aggregate
的实现,我认为这里不值得写。它可以以类似的方式适应 AfterEach
。