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 th开发者_JS百科e 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);
}
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();
}
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);
}
精彩评论