リストをカンマで区切る最も簡単な方法は?


104

Javaでリストをカンマで区切る最も明確な方法は何ですか?

私はそれを行ういくつかの方法を知っていますが、最良の方法は何であるか疑問に思っています(「最良」とは、最も効率的ではなく、最も明確かつ/または最も短いことを意味します。

リストがあり、ループして各値を出力したいと思います。各項目の間にコンマを印刷したいが、最後の項目の後(または最初の項目の前)は印刷したくない。

List --> Item ( , Item ) *
List --> ( Item , ) * Item

サンプルソリューション1:

boolean isFirst = true;
for (Item i : list) {
  if (isFirst) {
    System.out.print(i);        // no comma
    isFirst = false;
  } else {
    System.out.print(", "+i);   // comma
  }
}

サンプルソリューション2-サブリストを作成します。

if (list.size()>0) {
  System.out.print(list.get(0));   // no comma
  List theRest = list.subList(1, list.size());
  for (Item i : theRest) {
    System.out.print(", "+i);   // comma
  }
}

サンプルソリューション3:

  Iterator<Item> i = list.iterator();
  if (i.hasNext()) {
    System.out.print(i.next());
    while (i.hasNext())
      System.out.print(", "+i.next());
  }

これらは最初の項目を特別に扱います。代わりに最後のものを特別に扱うことができます。

ちなみに、Java 1.6 での実装方法List toString AbstractCollection次のとおりです(これはから継承されています)。

public String toString() {
    Iterator<E> i = iterator();
    if (! i.hasNext())
        return "[]";

    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (;;) {
        E e = i.next();
        sb.append(e == this ? "(this Collection)" : e);
        if (! i.hasNext())
            return sb.append(']').toString();
        sb.append(", ");
    }
}

最後の項目の後のカンマを回避するために、ループを早期に終了します。ところで、「(このコレクション)」を見たのは初めてです。これを呼び出すコードは次のとおりです。

List l = new LinkedList();
l.add(l);
System.out.println(l);

彼らが予期しないライブラリを使用していても、私はどんな解決策も歓迎します(正規表現?)。また、Java以外の言語でのソリューション(たとえば、Python / Rubyには散在関数があると思います。これはどのよう実装されますか?)

明確化:ライブラリとは、標準のJavaライブラリを意味します。他のライブラリについては、他の言語でそれらを検討し、それらがどのように実装されているかを知りたいと思っています。

EDITツールキットは同様の質問に言及しました:Javaの拡張forループの最後の反復

そしてもう1つ: ループの最後の要素は別の扱いに値しますか?


回答:


226

Java 8以降

StringJoinerクラスを使用:

StringJoiner joiner = new StringJoiner(",");
for (Item item : list) {
    joiner.add(item.toString());
}
return joiner.toString();

Streamおよびの使用Collectors

return list.stream().
       map(Object::toString).
       collect(Collectors.joining(",")).toString();

Java 7およびそれ以前

参照#285523

String delim = "";
for (Item i : list) {
    sb.append(delim).append(i);
    delim = ",";
}

1
状態を保存する非常に驚くべき方法!ほぼOO多態性です。ループごとの不要な割り当ては好きではありませんが、ifよりも効率的です。ほとんどのソリューションは、真実ではないことがわかっているテストを繰り返します。非効率ですが、おそらく最も明確です。リンクをありがとう!
13ren 2009年

1
私はこれが好きですが、賢くて意外なので、使用するのは適切ではないと思いました(意外は良くありません!)。しかし、どうしようもなかった。それについてはまだわかりません。しかし、それは非常に短いので、ヒントを与えるコメントがあれば簡単に解決できます。
13ren 2009年

6
@ 13ren:あなたとボブおじさんは、「賢くて意外な」コードについて話をする必要があります。
Stefan Kendall、

これを知らないまま何年も無駄に感じた^^;
湖の

なぜJavaはそのようなタスクを醜いコードに変える必要があるのですか?
エドゥアルド

82
org.apache.commons.lang3.StringUtils.join(list,",");

1
ソースを見つけました:svn.apache.org/viewvc/commons/proper/lang/trunk/src/java/org/…joinメソッドには9つのオーバーロードがあります。反復ベースのものは「サンプルソリューション3」のようなものです。インデックスベースのインデックスが使用するもの:if(i> startIndex){<セパレータを追加>}
13ren

私は本当に実装後です。関数で囲むことをお勧めしますが、実際には、区切り文字は改行である場合があり、各行は指定された深さまでインデントされています。しない限り... join(list、 "\ n" + indent)...それは常に機能しますか?申し訳ありませんが、声を出して考えています。
13ren 2009年

2
私の意見では、これは最もきれいで最も短い解決策です
JesperRønn-JensenMar

たぶん、list.iterator()?
Vanuan 2013

32

Java 8は、これを行うためのいくつかの新しい方法を提供します。

  • joinメソッドString
  • クラスjoiningからのストリームのコレクターCollectors
  • StringJoinerクラス。

例:

// Util method for strings and other char sequences
List<String> strs = Arrays.asList("1", "2", "3");
String listStr1 = String.join(",", strs);

// For any type using streams and collectors
List<Object> objs = Arrays.asList(1, 2, 3);
String listStr2 = objs.stream()
    .map(Object::toString)
    .collect(joining(",", "[", "]"));

// Using the new StringJoiner class
StringJoiner joiner = new StringJoiner(", ", "[", "]");
joiner.setEmptyValue("<empty>");
for (Integer i : objs) {
  joiner.add(i.toString());
}
String listStr3 = joiner.toString();

ストリームを使用するアプローチは、を前提としていimport static java.util.stream.Collectors.joining;ます。


これは私見です。Java8を使用している場合は、最良の答えです。
クレイジーな2015年


7

Spring Frameworkを使用している場合は、StringUtilsを使用して実行できます。

public static String arrayToDelimitedString(Object[] arr)
public static String arrayToDelimitedString(Object[] arr, String delim)
public static String collectionToCommaDelimitedString(Collection coll)
public static String collectionToCommaDelimitedString(Collection coll, String delim)

おかげで、それはどのように実装されますか?
13ren 2009年

6

JavaのList toString実装に基づく:

Iterator i = list.iterator();
for (;;) {
  sb.append(i.next());
  if (! i.hasNext()) break;
  ab.append(", ");
}

次のような文法を使用します。

List --> (Item , )* Item

最初に基づくのではなく最後に基づくことにより、リストの終わりを確認する同じテストでスキップカンマを確認できます。これはとてもエレガントだと思いますが、明確さについてはわかりません。


4
String delimiter = ",";
StringBuilder sb = new StringBuilder();
for (Item i : list) {
    sb.append(delimiter).append(i);
}
sb.toString().replaceFirst(delimiter, "");

4

Java 8を使用してこれを実現するかなりの方法があります。

List<String> list = Arrays.asList(array);
String joinedString = String.join(",", list);

TextUtils.join( "、"、list);
Arul Pandian

3
for(int i=0, length=list.size(); i<length; i++)
  result+=(i==0?"":", ") + list.get(i);

はい、それは少し不可解ですが、すでに投稿されているものの代替です。
cherouvim 2009年

1
私はコードがうまく見えると思います、私見はあなたの他の答えよりもきれいで、ほとんど「不可解」ではありません。Joinと呼ばれる方法でそれをまとめて、あなたの笑い声を上げてください。それでも、言語には本当に一般的な問題を解決するより良い方法があると思います。

@tarn:Python / perlのバックグラウンドがあるので、見栄えが良いと思います;)私も好きです
cherouvim 2009年

3

foreachループの1つのオプションは次のとおりです。

StringBuilder sb = new StringBuilder();
for(String s:list){
  if (sb.length()>0) sb.append(",");
  sb.append(s);
}

2
StringBuffer result = new StringBuffer();
for(Iterator it=list.iterator; it.hasNext(); ) {
  if (result.length()>0)
    result.append(", ");
  result.append(it.next());
}

更新:Dave Webbがコメントで言及したように、リストの最初の項目が空の文字列である場合、これは正しい結果を生成しない可能性があります。


meh ..ループ内にまだifがあります。
sfossen 2009年

foreachループを使用して短くすることができます。
Peter Lawrey

リストの最初の項目が空の文字列の場合、これは機能しません。
Dave Webb

@Dave Webb:はい、ありがとうございます。ただし、質問にはそのような要件はありません。
cherouvim 2009年

@cherovium:質問では、どの項目も空の文字列にはならないので、暗黙の要件です。CSVファイルを作成している場合、空のフィールドはかなり一般的です。
Dave Webb

2

私は通常これを行います:

StringBuffer sb = new StringBuffer();
Iterator it = myList.iterator();
if (it.hasNext()) { sb.append(it.next().toString()); }
while (it.hasNext()) { sb.append(",").append(it.next().toString()); }

Javaの実装に従って、これからこのチェックを行うと思いますが;)


これはサンプル3と同じロジックです。不要なことは何もしないので、気に入っています。しかし、それが最も明確かどうかはわかりません。ところで、リストが空のときに2つのテストを行わないようにすることで、if内にwhileを入れる方が少し効率的です。それはまた、私にはそれを少しはっきりさせます。
13ren 2009年

天国のために、StringBuilderを使用してください
クレイジー

2

(JVMで実行される)Groovyを使用できる場合:

def list = ['a', 'b', 'c', 'd']
println list.join(',')

ありがとう、でも実装に興味があります。これはどのように実装されますか?
13ren 2009年

2

ここから自分の回答をコピーして貼り付けます。)説明するソリューションの多くは、特に外部ライブラリに依存するもので、IMHOを少し上回っています。私がいつも使ってきたコンマ区切りのリストを実現するためのすっきりとした明確なイディオムがあります。条件付き(?)演算子に依存します。

編集:元のソリューションは正しいが、コメントによると最適ではない。もう一度試す:

int[] array = {1, 2, 3};
StringBuilder builder = new StringBuilder();
for (int i = 0 ;  i < array.length; i++)
       builder.append(i == 0 ? "" : ",").append(array[i]);

それでは、配列の宣言とStringBuilderを含む4行のコードを書きます。

2番目の編集:イテレーターを扱っている場合:

    List<Integer> list = Arrays.asList(1, 2, 3);
    StringBuilder builder = new StringBuilder();
    for (Iterator it = list.iterator(); it.hasNext();)
        builder.append(it.next()).append(it.hasNext() ? "," : "");

これと上記のstackoverflow.com/questions/668952/…は似ています。短くて明確ですが、イテレータしかない場合は、最初に変換する必要があります。非効率的ですが、このアプローチを明確にするには価値があるでしょうか?
13ren 2009年

文字列連結によって、StringBuilderの使用中に一時的なStringBuilderが作成されます。非効率的な。より良い(Javaのほうが好きですが、コードの実行がより良い)は、「if(i> 0){builder.append( '、');}」の後にbuilder.append(array [i]);が続くことになります。
エディ

はい、バイトコードを見ると正しいです。私はそのような単純な質問がそれほど複雑になるとは信じられません。コンパイラーがここで最適化できるかどうか。
Julien Chastang 2009年

第2の提供、うまくいけばより良いソリューション。
Julien Chastang 2009年

それらを分割した方がいいかもしれません(そのため、人々はどちらかに投票できます)。
13ren 2009年

1

私は通常、バージョン3に似たものを使用します。これはうまく機能しますc / c ++ / bash / ...:P


1

私はそれをコンパイルしませんでした...しかし、動作するはずです(または動作するようになります)。

public static <T> String toString(final List<T> list, 
                                  final String delim)
{
    final StringBuilder builder;

    builder = new StringBuilder();

    for(final T item : list)
    {
        builder.append(item);
        builder.append(delim);
    }

    // kill the last delim
    builder.setLength(builder.length() - delim.length());

    return (builder.toString());
}

私はこの方法が好きです、私は他のフォーマットを好みます。しかし、1つの小さな修正について述べると、リストが空の場合、これはIndexOutOfBounds例外をスローします。したがって、setLengthの前にチェックを行うか、Math.max(0、...)を使用します
tb-

1

これは非常に短く、非常に明確ですが、忍び寄る恐怖を私の感覚に与えます。特に文字列(charではない)の場合、さまざまな区切り文字に適応するのも少し厄介です。

for (Item i : list)
  sb.append(',').append(i);
if (sb.charAt(0)==',') sb.deleteCharAt(0);

Inspired by:Javaの拡張forループの最後の反復


1
StringBuffer sb = new StringBuffer();

for (int i = 0; i < myList.size(); i++)
{ 
    if (i > 0) 
    {
        sb.append(", ");
    }

    sb.append(myList.get(i)); 
}

これは、静的ユーティリティクラスに非常に簡単に埋め込むことができると同時に、非常に読みやすく理解しやすいことがわかります。また、リスト自体、ループ、区切り記号以外の追加の変数や状態は必要ありません。
Joachim H. Skeie

:これは、のようなものを提供しますItem1Item2, Item3, Item4,

天国では、StringBuilderを使用してください
クレイジー

1

少し前にブログで見つけたこのアプローチが少し好きです。残念ながら、ブログの名前/ URLを覚えていません。

次のようなユーティリティ/ヘルパークラスを作成できます。

private class Delimiter
{
    private final String delimiter;
    private boolean first = true;

    public Delimiter(String delimiter)
    {
        this.delimiter = delimiter;
    }

    @Override
    public String toString()
    {
        if (first) {
            first = false;
            return "";
        }

        return delimiter;
    }
}

ヘルパークラスの使用は次のように簡単です。

StringBuilder sb = new StringBuilder();
Delimiter delimiter = new Delimiter(", ");

for (String item : list) {
    sb.append(delimiter);
    sb.append(item);
}

注:「デリミタ」ではなく「デリミタ」である必要があります。
マイケルマイヤーズ

1

区切り文字が "、"であるため、次のいずれかを使用できます。

public class StringDelim {

    public static void removeBrackets(String string) {
        System.out.println(string.substring(1, string.length() - 1));
    }

    public static void main(String... args) {
        // Array.toString() example
        String [] arr = {"Hi" , "My", "name", "is", "br3nt"};
        String string = Arrays.toString(arr);
        removeBrackets(string);

        // List#toString() example
        List<String> list = new ArrayList<String>();
        list.add("Hi");
        list.add("My");
        list.add("name");
        list.add("is");
        list.add("br3nt");
        string = list.toString();
        removeBrackets(string);

        // Map#values().toString() example
        Map<String, String> map = new LinkedHashMap<String, String>();
        map.put("1", "Hi");
        map.put("2", "My");
        map.put("3", "name");
        map.put("4", "is");
        map.put("5", "br3nt");
        System.out.println(map.values().toString());
        removeBrackets(string);

        // Enum#toString() example
        EnumSet<Days> set = EnumSet.allOf(Days.class);
        string = set.toString();
        removeBrackets(string);
    }

    public enum Days {
        MON("Monday"),
        TUE("Tuesday"),
        WED("Wednesday"),
        THU("Thursday"),
        FRI("Friday"),
        SAT("Saturday"),
        SUN("Sunday");

        private final String day;

        Days(String day) {this.day = day;}
        public String toString() {return this.day;}
    }
}

区切り文字がそれ以外の場合、これは機能しません。


1

私はこの解決策が好きです:

String delim = " - ", string = "";

for (String item : myCollection)
    string += delim + item;

string = string.substring(delim.length());

StringBuilderも利用できると思います。


1

私の意見では、これは読んで理解するのが最も簡単です:

StringBuilder sb = new StringBuilder();
for(String string : strings) {
    sb.append(string).append(',');
}
sb.setLength(sb.length() - 1);
String result = sb.toString();

0

Pythonでは簡単

"、"。join(yourlist)

C#では、Stringクラスに静的メソッドがあります

String.Join( "、"、yourlistofstrings)

申し訳ありませんが、Javaについてはわかりませんが、他の言語について尋ねられたら、私はパイプを張ると思いました。Javaにも似たようなものがあると思います。


IIRC、.Netバージョンでは、末尾が表示されます。:-(

1
ただ、テスト、.NETやPythonには末尾の区切りません
タルン

1
ありがとう!私はそれのソースを見つけました:svn.python.org/view/python/branches/release22-branch/Objects/… 「Catenate everything」を検索してください。最後のアイテムのセパレータは省略されます。
13ren 2009年

@ 13renよくできました!それは役に立ちますか?私は、ロックを持っていたし、私はこれらの日Cでプログラムしないことを選択した理由をすぐに思い出した:P
タルン

@tarn、そうです、それが最後のアイテムでない場合にのみコマンドを追加するので、興味深い例です:if(i <seqlen-1){<セパレーターを追加>}
13ren

0

また、無条件に区切り文字列を追加し、ループの後に最後の余分な区切り文字を削除することもできます。次に、「リストが空の場合、この文字列を返す」を最初に使用すると、最後のチェックを回避できます(空のリストから文字を削除することはできません)。

だから問題は本当に:

「ループとifを考えると、これらを一緒にする最も明確な方法は何だと思いますか?」


0
public static String join (List<String> list, String separator) {
  String listToString = "";

  if (list == null || list.isEmpty()) {
   return listToString;
  }

  for (String element : list) {
   listToString += element + separator;
  }

  listToString = listToString.substring(0, separator.length());

  return listToString;
}

1
私はあなたが言うlistToString.substring(0, listToString.length()-separator.length());
つもりだっ

0
if (array.length>0)          // edited in response Joachim's comment
  sb.append(array[i]);
for (int i=1; i<array.length; i++)
  sb.append(",").append(array[i]);

リストをカンマで区切る最も明確な方法に基づいていますか(Java)?

このアイデアを使用する: ループの最後の要素は別の扱いに値しますか?


1
これが機能するためには、リストに少なくとも1つの要素があることを知っている必要があります。そうしないと、最初のforループがIndexOutOfBoundsExceptionでクラッシュします。
Joachim H. Skeie

@Joachimありがとう、もちろんあなたは正しい。私が書いたなんて醜い解決策です!に変更for (int i=0; i<1; i++)if (array.length>0)ます。
2013年

0
public String toString(List<Item> items)
{
    StringBuilder sb = new StringBuilder("[");

    for (Item item : items)
    {
        sb.append(item).append(", ");
    }

    if (sb.length() >= 2)
    {
        //looks cleaner in C# sb.Length -= 2;
        sb.setLength(sb.length() - 2);
    }

    sb.append("]");

    return sb.toString();
}

1
気づいたのは、TofuBeerが出し
Eblis

0

これまでのところ、どの回答も再帰を使用していません...

public class Main {

    public static String toString(List<String> list, char d) {
        int n = list.size();
        if(n==0) return "";
        return n > 1 ? Main.toString(list.subList(0, n - 1), d) + d
                  + list.get(n - 1) : list.get(0);
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList(new String[]{"1","2","3"});
        System.out.println(Main.toString(list, ','));
    }

}

0
private String betweenComma(ArrayList<String> strings) {
    String united = "";
    for (String string : strings) {
        united = united + "," + string;
    }
    return united.replaceFirst(",", "");
}

-1

方法

String join(List<Object> collection, String delimiter){
    StringBuilder stringBuilder = new StringBuilder();
    int size = collection.size();
    for (Object value : collection) {
        size --;
        if(size > 0){
            stringBuilder.append(value).append(delimiter);
        }
    }

    return stringBuilder.toString();
}

使用法

[1,2,3]の配列を考える

join(myArray, ",") // 1,2,3
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.