加入List <string>与Commas Plus"和"Last Element

Gab*_*ias 15 c# list

我知道我可以想出办法,但我想知道是否有更简洁的解决方案.总是有String.Join(", ", lList),lList.Aggregate((a, b) => a + ", " + b);但我想为最后一个添加一个例外,", and "作为其连接字符串.确实Aggregate()有一些指标值的地方,我可以用?谢谢.

key*_*rdP 22

你可以做到这一点

string finalString = String.Join(", ", myList.ToArray(), 0, myList.Count - 1) + ", and " + myList.LastOrDefault();
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,如果列表中只有一个项目,则不起作用 (10认同)

Dar*_*ren 11

这是一个解决方案,它使用空列表和列表,其中包含一个项目:

C#

return list.Count() > 1 ? string.Join(", ", list.Take(list.Count() - 1)) + " and " + list.Last() : list.FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)

VB

Return If(list.Count() > 1, String.Join(", ", list.Take(list.Count() - 1)) + " and " + list.Last(), list.FirstOrDefault())
Run Code Online (Sandbox Code Playgroud)


Car*_*ode 8

我使用以下扩展方法(也有一些代码保护):

public static string OxbridgeAnd(this IEnumerable<String> collection)
{
    var output = String.Empty;

    var list = collection.ToList();

    if (list.Count > 1)
    {
        var delimited = String.Join(", ", list.Take(list.Count - 1));

        output = String.Concat(delimited, ", and ", list.LastOrDefault());
    }

    return output;
}
Run Code Online (Sandbox Code Playgroud)

这是一个单元测试:

 [TestClass]
    public class GrammarTest
    {
        [TestMethod]
        public void TestThatResultContainsAnAnd()
        {
            var test = new List<String> { "Manchester", "Chester", "Bolton" };

            var oxbridgeAnd = test.OxbridgeAnd();

            Assert.IsTrue( oxbridgeAnd.Contains(", and"));
        }
    }
Run Code Online (Sandbox Code Playgroud)

编辑

此代码现在处理null和单个元素:

  public static string OxbridgeAnd(this IEnumerable<string> collection)
    {
        var output = string.Empty;

        if (collection == null) return null;

        var list = collection.ToList();

        if (!list.Any()) return output;

        if (list.Count == 1) return list.First();

        var delimited = string.Join(", ", list.Take(list.Count - 1));

        output = string.Concat(delimited, ", and ", list.LastOrDefault());

        return output;
    }
Run Code Online (Sandbox Code Playgroud)


Art*_*ous 7

此版本仅枚举一次值,并且适用于任意数量的值。

(改进了@Grastveit 的答案)

我将其转换为扩展方法并添加了一些单元测试。添加了一些空检查。我还修复了一个错误,如果values集合中的某个项目包含null,并且它是最后一个,则它将被完全跳过。String.Join()这与.NET Framework 中现在的行为方式不符。

#nullable enable
using System;
using System.Collections.Generic;
using System.Text;

namespace Helpers;

public static class StringJoinExtensions
{
    public static string JoinAnd<T>(this IEnumerable<T?> values,
        in string separator = ", ",
        in string lastSeparator = ", and ") => JoinAnd(values, new StringBuilder(), separator, lastSeparator).ToString();

    public static StringBuilder JoinAnd<T>(this IEnumerable<T?> values,
        StringBuilder sb,
        in string separator = ", ",
        in string lastSeparator = ", and ")
    {
        _ = values ?? throw new ArgumentNullException(nameof(values));
        _ = separator ?? throw new ArgumentNullException(nameof(separator));
        _ = lastSeparator ?? throw new ArgumentNullException(nameof(lastSeparator));

        using var enumerator = values.GetEnumerator();

        // add first item without separator
        if (enumerator.MoveNext())
        {
            sb.Append(enumerator.Current);
        }

        var nextItem = (hasValue: false, item: default(T?));
        // see if there is a next item
        if (enumerator.MoveNext())
        {
            nextItem = (true, enumerator.Current);
        }

        // while there is a next item, add separator and current item
        while (enumerator.MoveNext())
        {
            sb.Append(separator);
            sb.Append(nextItem.item);
            nextItem = (true, enumerator.Current);
        }

        // add last separator and last item
        if (nextItem.hasValue)
        {
            sb.Append(lastSeparator ?? separator);
            sb.Append(nextItem.item);
        }

        return sb;
    }
}
Run Code Online (Sandbox Code Playgroud)

单元测试

#nullable enable
using Xunit;
using System;
using System.Linq;
using Helpers;
using FluentAssertions;

namespace Helpers.Tests;

public class StringJoinExtensionsFixture
{
    [Theory]
    [InlineData("", "", null, null)]
    [InlineData("1", "1", null, null)]
    [InlineData("1 and 2", "1", "2", null)]
    [InlineData("1, 2 and 3", "1", "2", "3")]
    [InlineData(", 2 and 3", "", "2", "3")]
    public void ReturnsCorrectResults(string expectedResult,
         string string1, string string2, string string3)
    {
        var input = new[] { string1, string2, string3 }.Where(r => r != null);
        string actualResult = input.JoinAnd(", ", " and ");
        Assert.Equal(expectedResult, actualResult);
    }

    [Fact]
    public void ThrowsIfArgumentNulls()
    {
        Assert.Throws<ArgumentNullException>(() =>
             StringJoinExtensions.JoinAnd(default(string[])!, ", ", " and "));

        Assert.Throws<ArgumentNullException>(() =>
           StringJoinExtensions.JoinAnd(new[] { "1", "2" }, null!,
              " and "));

        Assert.Throws<ArgumentNullException>(() =>
           StringJoinExtensions.JoinAnd(new[] { "1", "2" }, "", null!));
    }

    [Fact]
    public void SeparatorsCanBeEmpty()
    {
        StringJoinExtensions.JoinAnd(new[] { "1", "2" }, "", ",")
            .Should().Be("1,2", "separator is empty");
        StringJoinExtensions.JoinAnd(new[] { "1", "2" }, ",", "")
            .Should().Be("12", "last separator is empty");
        StringJoinExtensions.JoinAnd(new[] { "1", "2" }, "", "")
            .Should().Be("12", "both separators are empty");
    }

    [Fact]
    public void ValuesCanBeNullOrEmpty()
    {
        StringJoinExtensions.JoinAnd(new[] { "", "2" }, "+", "-")
            .Should().Be("-2", "1st value is empty");
        StringJoinExtensions.JoinAnd(new[] { "1", "" }, "+", "-")
            .Should().Be("1-", "2nd value is empty");
        StringJoinExtensions.JoinAnd(new[] { "1", "2", "" }, "+", "-")
            .Should().Be("1+2-", "3rd value is empty");

        StringJoinExtensions.JoinAnd(new[] { null, "2" }, "+", "-")
            .Should().Be("-2", "1st value is null");
        StringJoinExtensions.JoinAnd(new[] { "1", null }, "+", "-")
            .Should().Be("1-", "2nd value is null");
        StringJoinExtensions.JoinAnd(new[] { "1", "2", null }, "+", "-")
            .Should().Be("1+2-", "3rd value is null");
    }
}
Run Code Online (Sandbox Code Playgroud)


Gra*_*eit 5

此版本枚举一次值,并使用任意数量的值:

public static string JoinAnd<T>(string separator, string sepLast, IEnumerable<T> values)
{
    var sb = new StringBuilder();
    var enumerator = values.GetEnumerator();

    if (enumerator.MoveNext())
    {
        sb.Append(enumerator.Current);
    }

    object obj = null;
    if (enumerator.MoveNext())
    {
        obj = enumerator.Current;
    }

    while (enumerator.MoveNext())
    {
        sb.Append(separator);
        sb.Append(obj);
        obj = enumerator.Current;
    }

    if (obj != null)
    {
        sb.Append(sepLast);
        sb.Append(obj);
    }

    return sb.ToString();
}
Run Code Online (Sandbox Code Playgroud)