C# 加入列表<;字符串>;连同逗号加上“;及;最后一个元素

C# 加入列表<;字符串>;连同逗号加上“;及;最后一个元素,c#,list,C#,List,我知道我能想出一个解决办法,但我想知道是否有更简洁的解决办法。总是有String.Join(“,”,lList)和lList.Aggregate((a,b)=>a+”,“+b)但是我想为最后一个添加一个异常,将和“作为其连接字符串。Aggregate()是否有我可以使用的索引值?谢谢。你可以这样做 string finalString = String.Join(", ", myList.ToArray(), 0, myList.Count - 1) + ", and " + myList.La

我知道我能想出一个解决办法,但我想知道是否有更简洁的解决办法。总是有
String.Join(“,”,lList)
lList.Aggregate((a,b)=>a+”,“+b)
但是我想为最后一个添加一个异常,将
和“
作为其连接字符串。
Aggregate()
是否有我可以使用的索引值?谢谢。

你可以这样做

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

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

public静态字符串OxbridgeAnd(此IEnumerable集合)
{
var输出=String.Empty;
var list=collection.ToList();
如果(list.Count>1)
{
var delimited=String.Join(“,”,list.Take(list.Count-1));
output=String.Concat(以“、和”分隔),list.LastOrDefault();
}
返回输出;
}
下面是它的单元测试:

 [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"));
        }
    }
[TestClass]
公共课语法
{
[测试方法]
public void testthattresultcontainsand()
{
var测试=新列表{“曼彻斯特”、“切斯特”、“博尔顿”};
var-oxbridgeAnd=test.oxbridgeAnd();
Assert.IsTrue(oxbridgeAnd.Contains(“、和”);
}
}
编辑

此代码现在处理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;
    }
public静态字符串OxbridgeAnd(此IEnumerable集合)
{
var输出=string.Empty;
if(collection==null)返回null;
var list=collection.ToList();
如果(!list.Any())返回输出;
if(list.Count==1)返回list.First();
var delimited=string.Join(“,”,list.Take(list.Count-1));
output=string.Concat(以“、和”分隔),list.LastOrDefault();
返回输出;
}

这里有一个解决方案,它可以处理空列表和包含单个项目的列表:

C# VB
此版本只枚举一次值,可用于任意数量的值:

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();
}
publicstaticstringjoinand(字符串分隔符、字符串sepLast、IEnumerable值)
{
var sb=新的StringBuilder();
变量枚举器=值。GetEnumerator();
if(枚举数.MoveNext())
{
sb.Append(枚举器当前);
}
objectobj=null;
if(枚举数.MoveNext())
{
obj=枚举数。当前值;
}
while(枚举数.MoveNext())
{
附加(分隔符);
某人附加(obj);
obj=枚举数。当前值;
}
如果(obj!=null)
{
某人附加(sepLast);
某人附加(obj);
}
使某人返回字符串();
}

此版本仅枚举一次值,并可处理任意数量的值

(对@Grastveit的改进)

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

#region Usings
using System;
using System.Collections.Generic;
using System.Text;
#endregion 

namespace MyHelpers
{
    public static class StringJoinExtensions
    {
        public static string JoinAnd<T>(this IEnumerable<T> values, 
             string separator, string lastSeparator = null)
        {
            if (values == null)
                throw new ArgumentNullException(nameof(values));
            if (separator == null)
                throw new ArgumentNullException(nameof(separator));

            var sb = new StringBuilder();
            var enumerator = values.GetEnumerator();

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

            bool objectIsSet = false;
            object obj = null;
            if (enumerator.MoveNext())
            {
                obj = enumerator.Current;
                objectIsSet = true;
            }

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

            if (objectIsSet)
            {
                sb.Append(lastSeparator ?? separator);
                sb.Append(obj);
            }

            return sb.ToString();
        }
    }
}
#区域使用
使用制度;
使用System.Collections.Generic;
使用系统文本;
#端区
命名空间MyHelpers
{
公共静态类扩展
{
公共静态字符串JoinAnd(此IEnumerable值,
字符串分隔符,字符串lastSeparator=null)
{
如果(值==null)
抛出新ArgumentNullException(nameof(values));
if(分隔符==null)
抛出新ArgumentNullException(nameof(separator));
var sb=新的StringBuilder();
变量枚举器=值。GetEnumerator();
if(枚举数.MoveNext())
sb.Append(枚举器当前);
bool objectIsSet=false;
objectobj=null;
if(枚举数.MoveNext())
{
obj=枚举数。当前值;
objectIsSet=true;
}
while(枚举数.MoveNext())
{
附加(分隔符);
某人附加(obj);
obj=枚举数。当前值;
objectIsSet=true;
}
如果(对象集)
{
sb.追加(最后一个分隔符??分隔符);
某人附加(obj);
}
使某人返回字符串();
}
}
}
下面是一些单元测试
#区域使用
使用我的助手;
使用Microsoft.VisualStudio.TestTools.UnitTesting;
使用制度;
使用System.Linq;
#端区
命名空间单元测试
{
[测试类]
公共类StringJoinExtensionFixture
{
[数据测试方法]
[数据行(“,”,null,null)]
[数据行(“1”、“1”、空、空)]
[数据行(“1和2”,“1”,“2”,空)]
[数据行(“1、2和3”、“1”、“2”、“3”)]
[数据行(“、2和3”、“2”、“3”)]
public void returnsRectResults(字符串expectedResult,
字符串1、字符串2、字符串3)
{
var input=new[]{string1,string2,string3}
。其中(r=>r!=null);
字符串actualResult=input.JoinAnd(“,”和“);
Assert.AreEqual(预期结果、实际结果);
}
[测试方法]
public void ThrowsIfArgumentNulls()
{
字符串[]值=默认值;
Assert.ThrowsException(()=>
StringJoinExtensions.JoinAnd(值“,”,“和”);
Assert.ThrowsException(()=>
StringJoinExtensions.JoinAnd(新[]{“1”,“2”},null,
"及");;
}
[测试方法]
公共无效LastSeparatorCanBeNull()
{
aresequal(“1,2”,新[]{“1”,“2”}
.JoinAnd(“,”,null),
“lastSeparator显式设置为null”);
aresequal(“1,2”,新[]{“1”,“2”}
.及(“,”),
Return If(list.Count() > 1, String.Join(", ", list.Take(list.Count() - 1)) + " and " + list.Last(), list.FirstOrDefault())
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();
}
#region Usings
using System;
using System.Collections.Generic;
using System.Text;
#endregion 

namespace MyHelpers
{
    public static class StringJoinExtensions
    {
        public static string JoinAnd<T>(this IEnumerable<T> values, 
             string separator, string lastSeparator = null)
        {
            if (values == null)
                throw new ArgumentNullException(nameof(values));
            if (separator == null)
                throw new ArgumentNullException(nameof(separator));

            var sb = new StringBuilder();
            var enumerator = values.GetEnumerator();

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

            bool objectIsSet = false;
            object obj = null;
            if (enumerator.MoveNext())
            {
                obj = enumerator.Current;
                objectIsSet = true;
            }

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

            if (objectIsSet)
            {
                sb.Append(lastSeparator ?? separator);
                sb.Append(obj);
            }

            return sb.ToString();
        }
    }
}
#region Usings
using MyHelpers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;
#endregion

namespace UnitTests
{
    [TestClass]
    public class StringJoinExtensionsFixture
    {
        [DataTestMethod]
        [DataRow("", "", null, null)]
        [DataRow("1", "1", null, null)]
        [DataRow("1 and 2", "1", "2", null)]
        [DataRow("1, 2 and 3", "1", "2", "3")]
        [DataRow(", 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.AreEqual(expectedResult, actualResult);
        }

        [TestMethod]
        public void ThrowsIfArgumentNulls()
        {
            string[] values = default;
            Assert.ThrowsException<ArgumentNullException>(() =>
                 StringJoinExtensions.JoinAnd(values, ", ", " and "));

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

        [TestMethod]
        public void LastSeparatorCanBeNull()
        {
            Assert.AreEqual("1, 2", new[] { "1", "2" }
               .JoinAnd(", ", null), 
                   "lastSeparator is set to null explicitly");
            Assert.AreEqual("1, 2", new[] { "1", "2" }
               .JoinAnd(", "), 
                   "lastSeparator argument is not specified");
        }

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

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

            Assert.AreEqual("-2", StringJoinExtensions.JoinAnd(
             new[] { null, "2" }, "+", "-"), "1st value is null");
            Assert.AreEqual("1-", StringJoinExtensions.JoinAnd(
             new[] { "1", null }, "+", "-"), "2nd value is null");
            Assert.AreEqual("1+2-", StringJoinExtensions.JoinAnd(
             new[] { "1", "2", null }, "+", "-"), "3rd value is null");
        }
    }
}
a = [a, b, c, d]
print(', '.join(a[0:-1]) + ', and ' + a[-1])
print(', '.join(a[0:-1]) + ' and ' + a[-1])