使用分隔符加入字符串

时间:2009-02-24 11:36:23

标签: algorithm language-agnostic string

将字符串列表加入组合分隔字符串的最佳方法是什么。我主要关注何时停止添加分隔符。我将使用C#作为我的示例,但我希望这与语言无关。

编辑:我没有使用StringBuilder使代码稍微简单。

使用For循环

for(int i=0; i < list.Length; i++)
{
    result += list[i];
    if(i != list.Length - 1)
        result += delimiter;
}

使用For循环设置之前的第一项

result = list[0];
for(int i = 1; i < list.Length; i++)
    result += delimiter + list[i];

这些对于IEnumerable不适用,因为你事先不知道列表的长度,所以

使用foreach循环

bool first = true;
foreach(string item in list)
{
    if(!first)
        result += delimiter;
    result += item;
    first = false;
}

foreach循环的变化

来自Jon的解决方案

StringBuilder builder = new StringBuilder();
string delimiter = "";
foreach (string item in list)
{
    builder.Append(delimiter);
    builder.Append(item);
    delimiter = ",";       
}
return builder.ToString();

使用迭代器

再次来自Jon

using (IEnumerator<string> iterator = list.GetEnumerator())
{
    if (!iterator.MoveNext())
        return "";
    StringBuilder builder = new StringBuilder(iterator.Current);
    while (iterator.MoveNext())
    {
        builder.Append(delimiter);
        builder.Append(iterator.Current);
    }
    return builder.ToString();
}

还有哪些其他算法?

24 个答案:

答案 0 :(得分:35)

由于不同的语言和平台处理不同的字符串,并为加入字符串列表提供不同级别的内置支持,因此不可能在此提供真正与语言无关的答案。你可以用两种不同的语言来获取相当多的相同的代码,而且在一种语言中它会很棒而在另一种语言中会很糟糕。

在C#中,您可以使用:

StringBuilder builder = new StringBuilder();
string delimiter = "";
foreach (string item in list)
{
    builder.Append(delimiter);
    builder.Append(item);
    delimiter = ",";       
}
return builder.ToString();

这将在除第一项之外的所有内容上添加逗号。类似的代码在Java中也会很好。

编辑:这是一个替代方案,有点像伊恩后来的答案,但正在研究一般IEnumerable<string>

// Change to IEnumerator for the non-generic IEnumerable
using (IEnumerator<string> iterator = list.GetEnumerator())
{
    if (!iterator.MoveNext())
    {
        return "";
    }
    StringBuilder builder = new StringBuilder(iterator.Current);
    while (iterator.MoveNext())
    {
        builder.Append(delimiter);
        builder.Append(iterator.Current);
    }
    return builder.ToString();
}

在原始答案后近5年编辑......

在.NET 4中,string.Join非常重载。有一个重载IEnumerable<T>会自动调用ToString,并且IEnumerable<string>会出现重载。因此,无论如何,您不再需要上面的代码......对于.NET。

答案 1 :(得分:22)

在.NET中,您可以使用String.Join method

string concatenated = String.Join(",", list.ToArray());

使用.NET Reflector,我们可以了解它是如何做到的:

public static unsafe string Join(string separator, string[] value, int startIndex, int count)
{
    if (separator == null)
    {
        separator = Empty;
    }
    if (value == null)
    {
        throw new ArgumentNullException("value");
    }
    if (startIndex < 0)
    {
        throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
    }
    if (count < 0)
    {
        throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
    }
    if (startIndex > (value.Length - count))
    {
        throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
    }
    if (count == 0)
    {
        return Empty;
    }
    int length = 0;
    int num2 = (startIndex + count) - 1;
    for (int i = startIndex; i <= num2; i++)
    {
        if (value[i] != null)
        {
            length += value[i].Length;
        }
    }
    length += (count - 1) * separator.Length;
    if ((length < 0) || ((length + 1) < 0))
    {
        throw new OutOfMemoryException();
    }
    if (length == 0)
    {
        return Empty;
    }
    string str = FastAllocateString(length);
    fixed (char* chRef = &str.m_firstChar)
    {
        UnSafeCharBuffer buffer = new UnSafeCharBuffer(chRef, length);
        buffer.AppendString(value[startIndex]);
        for (int j = startIndex + 1; j <= num2; j++)
        {
            buffer.AppendString(separator);
            buffer.AppendString(value[j]);
        }
    }
    return str;
}

答案 2 :(得分:8)

当一些语言在一行中提供对此的支持时,没有什么理由使它与语言无关,例如Python的

",".join(sequence)

有关详细信息,请参阅the join documentation

答案 3 :(得分:5)

在PHP的implode()中:

$string = implode($delim, $array);

答案 4 :(得分:5)

对于python,请确保你有一个字符串列表,否则','。join(x)将失败。 对于使用2.5 +的安全方法

delimiter = '","'
delimiter.join(str(a) if a else '' for a in list_object)

“str(a)if a else''”适用于None类型,否则str()最终会生成'None',这不是很好;)

答案 5 :(得分:4)

我总是添加分隔符,然后在必要时将其删除。这样,当你只关心做一次工作时,你不会为循环的每次迭代执行if语句。

StringBuilder sb = new StringBuilder();

foreach(string item in list){
    sb.Append(item);
    sb.Append(delimeter);
}

if (list.Count > 0) {
    sb.Remove(sb.Length - delimter.Length, delimeter.Length)
}

答案 6 :(得分:4)

List<string> aaa = new List<string>{ "aaa", "bbb", "ccc" };
string mm = ";";
return aaa.Aggregate((a, b) => a + mm + b);

你得到了

aaa;bbb;ccc

lambda非常方便

答案 7 :(得分:4)

我会以递归方式表达。

  • 检查字符串参数的数量是否为1.如果是,则将其返回。
  • 否则递归,但将前两个参数与它们之间的分隔符合并。

Common Lisp中的示例:

(defun join (delimiter &rest strings)
  (if (null (rest strings))
      (first strings)
      (apply #'join
             delimiter
             (concatenate 'string
                          (first strings)
                          delimiter
                          (second strings))
             (cddr strings))))

更惯用的方法是使用reduce,但这会扩展到几乎与上述完全相同的说明:

(defun join (delimiter &rest strings)
  (reduce (lambda (a b)
            (concatenate 'string a delimiter b))
          strings))

答案 8 :(得分:3)

问题是计算机语言很少有字符串布尔值,即字符串类型的方法可以做任何有用的事情。 SQL Server至少有[not] null和nullif,它们在组合时解决了分隔符问题,顺便说一下:isnotnull(nullif(columnvalue,“”),“,”+ columnvalue))

问题在于,在语言中有布尔,并且有字符串,除了丑陋的编码形式之外,从来不会遇到twain,例如。

concatstring = string1 +“,”+ string2; if(fubar)     concatstring + = string3 concatstring + = string4等

我已经大力避免所有这些丑陋,玩逗号游戏和连接加入,但我仍然留下了一些,包括SQL Server错误,当我错过了一个逗号和变量是空。

乔纳森

答案 9 :(得分:2)

在C#中,您可以使用String.Join(separator,string_list)

答案 10 :(得分:1)

我认为做这样的事情的最佳方法是(我将使用伪代码,因此我们将使其真正与语言无关):

function concat(<array> list, <boolean> strict):
  for i in list:
    if the length of i is zero and strict is false:
      continue;
    if i is not the first element:
      result = result + separator;
    result = result + i;
  return result;

concat()的第二个参数strict是一个标志,用于了解是否必须在连接中考虑最终的空字符串。

我习惯不考虑添加最终分隔符;另一方面,如果strict为false,结果字符串可能没有像“A,B ,,, F”这样的东西,只要分隔符是逗号,而是显示为“A,B,F”。

答案 11 :(得分:1)

在Java 8中,我们可以使用:

List<String> list = Arrays.asList(new String[] { "a", "b", "c" });
System.out.println(String.join(",", list)); //Output: a,b,c

要有前缀和后缀,我们可以做

StringJoiner joiner = new StringJoiner(",", "{", "}");
list.forEach(x -> joiner.add(x));
System.out.println(joiner.toString()); //Output: {a,b,c}

在Java 8之前,你可以像Jon的回答那样做

StringBuilder sb = new StringBuilder(prefix);
boolean and = false;
for (E e : iterable) {        
    if (and) {
        sb.append(delimiter);
    }
    sb.append(e);
    and = true;
}
sb.append(suffix);

答案 12 :(得分:1)

看过3次Python回答,但没有Ruby?!?!?

代码的第一部分声明了一个新数组。然后你可以调用.join()方法并传递分隔符,它将返回一个中间带分隔符的字符串。我相信join方法在连接之前会对每个项调用.to_s方法。

["ID", "Description", "Active"].join(",")
>> "ID, Description, Active"

这在将元编程与数据库交互相结合时非常有用。

有人知道c#是否有类似于这种语法糖的东西吗?

答案 13 :(得分:1)

这是C#中的一个工作解决方案,在Java中,你可以在迭代器上使用类似的。

        string result = string.Empty; 

        // use stringbuilder at some stage.
        foreach (string item in list)
            result += "," + item ;

        result = result.Substring(1);
        // output:  "item,item,item"

如果使用.NET,您可能希望使用扩展方法,以便您可以这样做 的 list.ToString( “”) 有关详细信息,请查看Separator Delimited ToString for Array, List, Dictionary, Generic IEnumerable

// contains extension methods, it must be a static class.
public static class ExtensionMethod
{
    // apply this extension to any generic IEnumerable object.
    public static string ToString<T>(this IEnumerable<T> source,
      string separator)
    {
        if (source == null)
           throw new ArgumentException("source can not be null.");

        if (string.IsNullOrEmpty(separator))
           throw new ArgumentException("separator can not be null or empty.");

        // A LINQ query to call ToString on each elements
        // and constructs a string array.
        string[] array =
         (from s in source
          select s.ToString()
          ).ToArray();

        // utilise builtin string.Join to concate elements with
        // customizable separator.
        return string.Join(separator, array);
    }
}

编辑:出于性能原因,请使用此线程中提到的字符串构建器解决方案替换串联代码。

答案 14 :(得分:1)

由于您标记了此语言不可知,

这是你在python中的方法

# delimiter can be multichar like "| trlalala |"
delimiter = ";"
# sequence can be any list, or iterator/generator that returns list of strings
result = delimiter.join(sequence)
#result will NOT have ending delimiter 

编辑:我看到有几个人听到了答案。抱歉复制

答案 15 :(得分:0)

string result = "";
foreach(string item in list)
{
    result += delimiter + item;
}
result = result.Substring(1);

编辑:当然,您不会使用此算法或任何一种算法来连接字符串。使用C#/ .NET,您可能使用StringBuilder:

StringBuilder sb = new StringBuilder();
foreach(string item in list)
{
    sb.Append(delimiter);
    sb.Append(item);
}
string result = sb.ToString(1, sb.Length-1);

这个解决方案的变体:

StringBuilder sb = new StringBuilder(list[0]);
for (int i=1; i<list.Count; i++)
{
    sb.Append(delimiter);
    sb.Append(list[i]);
}
string result = sb.ToString();

两种解决方案都不包含任何错误检查。

答案 16 :(得分:0)

来自http://dogsblog.softwarehouse.co.zw/post/2009/02/11/IEnumerable-to-Comma-Separated-List-(and-more).aspx

我开发时的宠物仇恨正在制作一个逗号分隔的ID列表,它很简单但总是有丑陋的代码....常见的解决方案是循环并在每个项目后面加一个逗号然后删除最后一个字符,或者有一个if语句来检查你是否在列表的开头或结尾。下面是一个可以在任何IEnumberable上使用的解决方案,即List,Array等。它也是我能想到的最有效的方法,因为它依赖于赋值,这比编辑字符串或使用if更好。

public static class StringExtensions
{
    public static string Splice<T>(IEnumerable<T> args, string delimiter)
    {
        StringBuilder sb = new StringBuilder();
        string d = "";
        foreach (T t in args)
        {
            sb.Append(d);
            sb.Append(t.ToString());
            d = delimiter;
        }
        return sb.ToString();
    }
}

现在它可以与任何IEnumerable一起使用,例如。

StringExtensions.Splice(billingTransactions.Select(t =&gt; t.id),“,”)

给我们31,32,35

答案 17 :(得分:0)

在.NET中,如果可能的话,我会使用String.join方法,它允许您指定分隔符和字符串数组。可以使用ToArray将列表转换为数组,但我不知道它的性能会受到什么影响。

你提到的三种算法是我会使用的(我喜欢第二种,因为它没有if语句,但如果长度未知,我将使用第三种,因为它不会复制代码) 。第二个仅在列表不为空时才起作用,因此可能需要另一个if语句。

第四个变体可能是在每个连接的元素前放置一个分隔符,然后从结果中删除第一个分隔符。

如果你在循环中连接字符串,请注意,对于非平凡的情况,使用字符串构建器将大大超过重复的字符串连接。

答案 18 :(得分:0)

对于java,此question或此question已给出了非常完整的答案。

这是在Apache Commons中使用StringUtils.join

String result = StringUtils.join(list, ", ");

答案 19 :(得分:0)

在Clojure中,你可以使用clojure.contrib.str-utils / str-join:

(str-join ", " list)

但对于实际的算法:

(reduce (fn [res cur] (str res ", " cur)) list)

答案 20 :(得分:0)

Groovy还有一个String Object.join(String)方法。

答案 21 :(得分:0)

您可以编写自己的方法AppendTostring(string,delimiter),当且仅当字符串不为空时才附加分隔符。然后你只需在任何循环中调用该方法,而不必担心何时追加和何时不追加。

编辑:当然,如果可用的话,最好在方法中使用某种StringBuffer。

答案 22 :(得分:0)

这就是python解决问题的方法:

','.join(list_of_strings)

虽然

,我从来不会理解在微不足道的情况下对'算法'的需求

答案 23 :(得分:0)

Java(来自Jon的解决方案):

    StringBuilder sb = new StringBuilder();
    String delimiter = "";
    for (String item : items) {
        sb.append(delimiter).append(item);
        delimeter = ", ";
    }
    return sb.toString();