繁体   English   中英

从集合/数组/列表创建逗号分隔字符串的最复杂方法?

[英]The most sophisticated way for creating comma-separated Strings from a Collection/Array/List?

在我使用数据库的过程中,我注意到我编写了查询字符串,并且在这个字符串中,我必须在列表/数组/集合中的 where 子句中设置一些限制。 应该是这样的:

select * from customer 
where customer.id in (34, 26, ..., 2);

您可以通过将其简化为您拥有字符串集合并希望仅在一个字符串中创建此字符串的逗号分隔列表的问题来简化此问题。

我到目前为止使用的方法是这样的:

String result = "";
boolean first = true;
for(String string : collectionOfStrings) {
    if(first) {
        result+=string;
        first=false;
    } else {
        result+=","+string;
    }
}

但这是你可以看到的非常丑陋。 乍一看,您无法看到那里发生了什么,尤其是当构造的字符串(如每个 SQL 查询)变得复杂时。

你的(更)优雅的方式是什么?

使用Google Guava APIjoin方法:

Joiner.on(",").join(collectionOfStrings);

注意:这个答案在 11 年前写的时候很好,但是现在有更好的选择可以在一行中更干净地做到这一点,无论是仅使用 Java 内置类还是使用实用程序库。 请参阅下面的其他答案。


由于字符串是不可变的,如果您要更改代码中的字符串,您可能需要使用 StringBuilder 类。

StringBuilder 类可以被看作是一个可变的 String 对象,它在其内容被改变时分配更多的内存。

通过处理多余的尾随逗号,可以更清晰、更有效地写出问题中的原始建议:

    StringBuilder result = new StringBuilder();
    for(String string : collectionOfStrings) {
        result.append(string);
        result.append(",");
    }
    return result.length() > 0 ? result.substring(0, result.length() - 1): "";

我只是看了今天这样做的代码。 这是 AviewAnew 答案的变体。

collectionOfStrings = /* source string collection */;
String csList = StringUtils.join(collectionOfStrings.toArray(), ",");

我们使用的StringUtils (<-- commons.lang 2.x,或commons.lang 3.x 链接)来自Apache Commons

我编写该循环的方式是:

StringBuilder buff = new StringBuilder();
String sep = "";
for (String str : strs) {
    buff.append(sep);
    buff.append(str);
    sep = ",";
}
return buff.toString();

不要担心 sep 的性能。 一个任务非常快。 无论如何,热点往往会剥离循环的第一次迭代(因为它通常必须处理诸如空值和单态/双态内联检查之类的奇怪问题)。

如果你经常使用它(不止一次),把它放在一个共享方法中。

关于如何将 id 列表插入 SQL 语句的 stackoverflow 上还有另一个问题。

从 Java 8 开始,您可以使用:

我发现迭代器习语很优雅,因为它对更多元素进行了测试(为简洁起见,省略了空/空测试):

public static String convert(List<String> list) {
    String res = "";
    for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
        res += iterator.next() + (iterator.hasNext() ? "," : "");
    }
    return res;
}

对此有很多手动解决方案,但我想重申并更新上面 Julie 的回答。 使用google collections Joiner class

Joiner.on(", ").join(34, 26, ..., 2)

它处理 var args、iterables 和数组,并正确处理多个字符的分隔符(与 gimmel 的回答不同)。 如果需要,它还会处理列表中的空值。

String.join(", ", collectionOfStrings)

在 Java8 api 中可用。

替代(无需添加谷歌番石榴依赖):

Joiner.on(",").join(collectionOfStrings);

这是我根据先前建议的组合构建的令人难以置信的通用版本:

public static <T> String buildCommaSeparatedString(Collection<T> values) {
    if (values==null || values.isEmpty()) return "";
    StringBuilder result = new StringBuilder();
    for (T val : values) {
        result.append(val);
        result.append(",");
    }
    return result.substring(0, result.length() - 1);
}

你可以试试

List collections = Arrays.asList(34, 26, "...", 2);
String asString = collection.toString();
// justValues = "34, 26, ..., 2"
String justValues = asString.substring(1, asString.length()-1);

这将是迄今为止最短的解决方案,除了使用 Guava 或 Apache Commons

String res = "";
for (String i : values) {
    res += res.isEmpty() ? i : ","+i;
}

适合 0,1 和 n 元素列表。 但是您需要检查空列表。 我在 GWT 中使用它,所以没有 StringBuilder 我很好。 对于只有几个元素的短列表,其他地方也可以;)

我认为这不是一个好主意,像你正在做的那样构造连接 where 子句值的 sql :

SELECT.... FROM.... WHERE ID IN( value1, value2,....valueN)

valueX来自字符串列表。

首先,如果您正在比较字符串,它们必须被引用,如果字符串内部可以有引号,这并不是微不足道的。

其次,如果值来自用户或其他系统,则有可能进行 SQL 注入攻击。

它更冗长,但你应该做的是创建一个这样的字符串:

SELECT.... FROM.... WHERE ID IN( ?, ?,....?)

然后使用Statement.setString(nParameter,parameterValue)绑定变量。

如果有人最近偶然发现了这一点,我使用 Java 8 reduce()添加了一个简单的变体。 它还包括其他人已经提到的一些解决方案:

import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang.StringUtils;    

import com.google.common.base.Joiner;

public class Dummy {
  public static void main(String[] args) {

    List<String> strings = Arrays.asList("abc", "de", "fg");
    String commaSeparated = strings
        .stream()
        .reduce((s1, s2) -> {return s1 + "," + s2; })
        .get();

    System.out.println(commaSeparated);

    System.out.println(Joiner.on(',').join(strings));

    System.out.println(StringUtils.join(strings, ","));

  }
}

在 Android 中你应该使用这个:

TextUtils.join(",",collectionOfStrings.toArray());

处理这个问题的另一种方法。 不是最简短的,但它很高效并且可以完成工作。

/**
 * Creates a comma-separated list of values from given collection.
 * 
 * @param <T> Value type.
 * @param values Value collection.
 * @return Comma-separated String of values.
 */
public <T> String toParameterList(Collection<T> values) {
   if (values == null || values.isEmpty()) {
      return ""; // Depending on how you want to deal with this case...
   }
   StringBuilder result = new StringBuilder();
   Iterator<T> i = values.iterator();
   result.append(i.next().toString());
   while (i.hasNext()) {
      result.append(",").append(i.next().toString());
   }
   return result.toString();
}

有一些第三方 Java 库提供了字符串连接方法,但您可能不想开始使用库来处理诸如此类的简单事情。 我只想创建一个像这样的辅助方法,我认为它比你的版本好一点,它使用 StringBuffer,如果你需要连接许多字符串,它会更有效,并且它适用于任何类型的集合。

public static <T> String join(Collection<T> values)
{
    StringBuffer ret = new StringBuffer();
    for (T value : values)
    {
        if (ret.length() > 0) ret.append(",");
        ret.append(value);
    }
    return ret.toString();
}

使用 Collection.toString() 的另一个建议较短,但这依赖于 Collection.toString() 以非常特定的格式返回字符串,我个人不想依赖它。

如果您使用 Spring,您可以执行以下操作:

StringUtils.arrayToCommaDelimitedString(
    collectionOfStrings.toArray()
)

(包 org.springframework.util)

虽然我认为你最好的选择是使用 Guava 的 Joiner,但如果我要手动编码,我发现这种方法比“第一个”标志或切掉最后一个逗号更优雅。

private String commas(Iterable<String> strings) {
    StringBuilder buffer = new StringBuilder();
    Iterator<String> it = strings.iterator();
    if (it.hasNext()) {
        buffer.append(it.next());
        while (it.hasNext()) {
            buffer.append(',');
            buffer.append(it.next());
        }
    }

    return buffer.toString();
}

如果你有一个数组,你可以这样做:

Arrays.asList(parameters).toString()

我不确定这有多“复杂”,但肯定要短一些。 它将适用于各种不同类型的集合,例如 Set<Integer>、List<String> 等。

public static final String toSqlList(Collection<?> values) {

    String collectionString = values.toString();

    // Convert the square brackets produced by Collection.toString() to round brackets used by SQL
    return "(" + collectionString.substring(1, collectionString.length() - 1) + ")";
}

读者练习:修改此方法,使其正确处理空/空集合:)

Join 'methods' 在 Arrays 和扩展AbstractCollections但不覆盖toString()方法的类中可用(就像java.util几乎所有集合)。

例如:

String s= java.util.Arrays.toString(collectionOfStrings.toArray());
s = s.substing(1, s.length()-1);// [] are guaranteed to be there

这是一种非常奇怪的方式,因为它仅适用于 SQL 明智的数字等数据。

我刚刚为我的图书馆美元登记了一个测试:

@Test
public void join() {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    String string = $(list).join(",");
}

使用一个静态导入就创建了一个围绕列表/数组/字符串/等的流畅包装器: $

注意

使用范围可以将前面的列表重写为$(1, 5).join(",")

另一种选择,基于我在这里看到的(稍作修改)。

public static String toString(int[] numbers) {
    StringBuilder res = new StringBuilder();
    for (int number : numbers) {
        if (res.length() != 0) {
            res.append(',');
        }
        res.append(number);
    }
    return res.toString();
}
List<String> collectionOfStrings = // List of string to concat
String csvStrings = StringUtils.collectionToDelimitedString(collectionOfStrings, ",");

来自 springframeowrk 的 StringUtils:spring-core

IN 表达式的好处在于,如果您有重复的值,它不会改变结果。 因此,只需复制第一项并处理整个列表。 这假设列表中至少有一项。 如果没有项目,我建议先检查一下,然后根本不执行 SQL。

这可以解决问题,它正在做什么并且不依赖任何外部库:

StringBuffer inString = new StringBuffer(listOfIDs.get(0).toString());
for (Long currentID : listOfIDs) {
  inString.append(",").append(currentID);
}

使代码丑陋的是第一种情况的特殊处理。 这个小片段中的大部分行都专门用于处理代码的日常工作,而不是处理这种特殊情况。 这就是像 gimel 那样的替代方案,通过将特殊处理移到循环之外来解决。 有一种特殊情况(好吧,您可以将 start 和 end 都视为特殊情况 - 但只有其中一种需要特殊处理),因此在循环内处理它会不必要地复杂化。

String commaSeparatedNames = namesList.toString().replaceAll( "[\\[|\\]| ]", "" );  // replace [ or ] or blank

字符串表示由集合元素的列表组成,按其迭代器返回的顺序排列,括在方括号(“[]”)中。 相邻元素由字符“,”(逗号和空格)分隔。

抽象集合 javadoc

您可以使用 LINQ(到 SQL),并且可以使用 MS 的动态查询 LINQ 示例。 http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

List token=new ArrayList(result); 最终的 StringBuilder builder = new StringBuilder();

    for (int i =0; i < tokens.size(); i++){
        builder.append(tokens.get(i));
        if(i != tokens.size()-1){
            builder.append(TOKEN_DELIMITER);
        }
    }

builder.toString();

有一个简单的方法。 您可以在一行中获得结果。

String memberIdsModifiedForQuery = memberIds.toString().replace("[", "(").replace("]", ")");

要获得完整的想法,请检查以下代码

 public static void main(String[] args) {       
        List<Integer>memberIds=new ArrayList<Integer>();  //This contain member ids we want to process
        //adding some sample values for example
        memberIds.add(3); 
        memberIds.add(4);
        memberIds.add(2);
        String memberIdsModifiedForQuery = memberIds.toString().replace("[", "(").replace("]", ")"); //here you will get (3,4,5) That you can directly use in query
        System.out.println(memberIdsModifiedForQuery);
        String exampleQuery="select * from customer where customer.id in "+memberIdsModifiedForQuery+" ";
    }

android 中将 List 转换为逗号分隔字符串的最简单方法是使用android.text.TextUtils

 ArrayList<String>Myli = new ArrayList<String>();
 String ArayCommase=android.text.TextUtils.join(",", Myli);
java.util.List<String> lista = new java.util.ArrayList<String>();
lista.add("Hola");
lista.add("Julio");
System.out.println(lista.toString().replace('[','(').replace(']',')'));

$~(Hola, Julio)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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