简体   繁体   中英

How to Build String from a Collection of Names

I have a collection of first names which I need to combine into a comma separated string.

The generated string needs to adhere to proper grammar.

If the collection contains one name, then the output should be just that name:

John

If the collection contains two names, then the output should be separated by the word "and":

John and Mary

If the collection contains three or more names, then the output should be comma delimited, and the last name should have the word "and" before it:

John, Mary, and Jane

Here is the code I came up with. Its not very elegant and I'd like to know if there is a better way to accomplish this in C# (4.0 is OK).

List<string> firstNames = new List<string>();
firstNames.Add("John");
firstNames.Add("Mary");
firstNames.Add("Jane");

string names = string.Empty;
for (int i = 0; i < firstNames.Count; i++)
{
    if (i == 1 && firstNames.Count == 2)
    {
        names += " and ";
    }
    else if (firstNames.Count > 2 && i > 0 && i != firstNames.Count - 1)
    {
        names += ", ";
    }
    else if (i != 0 && i == firstNames.Count - 1)
    {
        names += ", and ";
    }

    names += firstNames[i];
}

I don't think it will get more elegant than:

 if (names.Count == 0)
     return "";

 if (names.Count == 1)
     return names[0];

 if (names.Count == 2)
     return names[0] + " and " + names[1];

 return String.Join(", ", names.Take(names.Count - 1)) +
     ", and "  + names[names.Count - 1];

I haven't compiled this, but I think you get the idea.

EDIT: Shorter, but less readable:

 if (names.Count <= 2)
     return String.Join(" and ", names);

 return String.Join(", ", names.Take(names.Count - 1)) + 
     ", and "  + names[names.Count - 1];

I would do something like this:

using System;
using System.Collections.Generic;

class Program {

    static void Main(string[] args) {
        List<string> firstNames = new List<string>();
        firstNames.Add("John");
        firstNames.Add("Mary");
        firstNames.Add("Jane");
        Console.WriteLine(NamesString(firstNames));
    }

    static string NamesString(List<string> firstNames) {
        switch (firstNames.Count) {
        case 0:
            return string.Empty;
        case 1:
            return firstNames[0];
        case 2:
            return string.Join(" and ", firstNames.ToArray());
        default:
            return string.Format("{0} and {1}",
                string.Join(", ", firstNames.ToArray(), 0, firstNames.Count - 1),
                firstNames[firstNames.Count - 1]);
        }
    }
}

EDIT : actually should be

        default:
            return string.Format("{0}, and {1}",

if you want a comma before the last "and".

        string a=string.Join(",", FirstNames.ToArray());
        if (FirstNames.Count == 1)
            a.Replace(",", "");
        else if (FirstNames.Count == 2)
            a.Replace(",", " and ");
        else
        {
            int i = a.LastIndexOf(",");
            a = a.Substring(1, i) + a.Substring(i).Replace(",", " and ");
        }
    static string JoinNames(List<string> firstNames)
    {
        int count = firstNames.Count;
        if(count == 1)
        {
            return firstNames[0];
        }

        if(count > 1)
        {
            return string.Join(", ", firstNames.Take(count - 1).ToArray()) + " and " + firstNames[count - 1];
        }
        return string.Empty;
    }
List<string> firstNames = new List<string>();
firstNames.Add("John");
firstNames.Add("Mary");
firstNames.Add("Jane");

StringBuilder names = new StringBuilder();
for (int i = 0; i < firstNames.Count; i++)
{
    if((i-1) == firstNames.Count && names.length > 0)
         names.AppendFormat(" and {0}", names[i]);
    else if(names.length > 0)
         names.AppendFormat(", {0}", names[i]);    
}
return names.ToString();

I think this is the best way.

List<string> firstNames = new List<string>();
firstNames.Add("John");
firstNames.Add("Mary");
firstNames.Add("Jane");
int cnt = 0;
string names = string.Empty;
while (cnt<=firstName.Count)
{
    string separator = "";

    if (firstName.Count - cnt > 1) separator = ", ";

    else if (firstName.Count - cnt = 1) separator = ", and ";

    else separator = "";

    names += firstName[cnt] + separator;

    cnt += 1;


}

Here is an interesting solution:

        //code
        List<string> firstNames = new List<string>();
        firstNames.Add("John");
        firstNames.Add("Mary");
        firstNames.Add("Jane");

        StringBuilder sb = new StringBuilder();
        firstNames.Take(firstNames.Count - 1).ToList().ForEach(fn => AddString(fn, sb));
        sb.Append(", and " + firstNames.Last());

    //Helper Function
    public void AddString (string fn, StringBuilder sb)
    {
        if (sb.Length != 0)
        {
            sb.Append(", ");
        }
        sb.Append(fn);
    }

Try this on for size:

            List<string> firstNames = new List<string>();
            firstNames.Add("John");
            firstNames.Add("Mary");
            firstNames.Add("Jane");

            // Only do this if there is more than one name
            if (firstNames.Count > 1)
            {
                string separator = ", ";

                // Join the names, using ", " as a separator
                string names = String.Join(seperator, firstNames.ToArray());

                // Insert "and" before the last comma
                names = names.Insert(names.LastIndexOf(separator), ", and ");

                // Remove the last comma
                names = names.Remove(names.LastIndexOf(separator), separator.Length);
            }
var a = String.Join(", ", firstNames.Skip(1).ToArray()) + (firstNames.Count < 2 ? "" : ", and ") + firstNames.Take(1).FirstOrDefault();

I prefer the code that is the most readable. You have 4 punctuation cases to consider when adding a name to a list, so just spell them out.

static string Combine(List<string> names)
{
    var sb = new StringBuilder();
    for (int i = 0; i < names.Count; i++)
    {
        if (i == 0) //at start of a list
            {}

        else if (i < names.Count - 1) //in middle of list
            sb.Append(", ");

        else if( names.Count == 2 ) //at end of a list with 2 elements
            sb.Append(" and ");

        else //at end of a list with 3 or more elements
            sb.Append(", and ");

        sb.Append(names[i]);
    }
    return sb.ToString();
}
public string Combine(List<string> names)
{
    if (names == null || names.Count == 0)
    {
        return string.Empty;
    }

    var sb = new StringBuilder();
    sb.Append(names[0]);

    //Handle Special Case of 2 names
    if (names.Count == 2)
    {
        sb.Append(" and " + names[1])
        return sb.ToString();
    }

    for (int i = 1; i < names.Count; i++)          
    {
        if (i == (names.Count -1))
        { 
            sb.Append(", and " + names[i]);
        }
        else
        {
            sb.Append(", " + names[i]);
        }
    }

    return sb.ToString(); 
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM