web-dev-qa-db-ja.com

ArrayListを文字列に変換する最良の方法

文字列として完全に出力したいArrayListがあります。基本的にはタブで区切られた各要素のtoStringを使って順番に出力したいです。これを行うための迅速な方法はありますか?それをループして(あるいは各要素を削除して)Stringに連結することもできますが、これは非常に遅いと思います。

353
Juan Besa

基本的に、ループを使用してArrayListを反復することが唯一の選択肢です。

このコードを使用しないでください。この回答の最後まで読んで、それがなぜ望ましくないのか、そして代わりにどのコードを使用する必要があるのか​​を確認してください。

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

String listString = "";

for (String s : list)
{
    listString += s + "\t";
}

System.out.println(listString);

実際のところ、javacコンパイラはappendに対する一連のStringBuilder操作として文字列連結を最適化するので、文字列連結はまさに問題ありません。上記のプログラムのforループからのバイトコードの逆アセンブリの一部です。

   61:  new #13; //class Java/lang/StringBuilder
   64:  dup
   65:  invokespecial   #14; //Method Java/lang/StringBuilder."<init>":()V
   68:  aload_2
   69:  invokevirtual   #15; //Method Java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   72:  aload   4
   74:  invokevirtual   #15; //Method Java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   77:  ldc #16; //String \t
   79:  invokevirtual   #15; //Method Java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   82:  invokevirtual   #17; //Method Java/lang/StringBuilder.toString:()Ljava/lang/String;

見てわかるように、コンパイラーはStringBuilderを使用してそのループを最適化しているので、パフォーマンスはそれほど問題にならないはずです。

(一見すると、StringBuilderはループの繰り返しごとにインスタンス化されているので、最も効率的なバイトコードではないかもしれません。明示的にStringBuilderをインスタンス化して使用すると、パフォーマンスが向上します。)

実際、私は、どんな種類の出力でも(ディスクまたは画面へ)、文字列連結のパフォーマンスを心配するよりも少なくとも一桁遅くなると思います。

編集: コメントで指摘されているように、上記のコンパイラの最適化は確かに各反復でStringBuilderの新しいインスタンスを作成しています。 (これは私が以前に書き留めたものです。)

最も最適化されたテクニックは Paul Tomblin による応答です。これはStringBuilderループの外側で単一のforオブジェクトをインスタンス化するだけなのでです。

上記のコードを次のように書き換えます。

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

StringBuilder sb = new StringBuilder();
for (String s : list)
{
    sb.append(s);
    sb.append("\t");
}

System.out.println(sb.toString());

このバイトコードで証明されているように、ループの外側でStringBuilderを一度だけインスタンス化し、appendメソッドを2回呼び出すだけです(これは、StringBuilderとループのインスタンス化を示しています)。

   // Instantiation of the StringBuilder outside loop:
   33:  new #8; //class Java/lang/StringBuilder
   36:  dup
   37:  invokespecial   #9; //Method Java/lang/StringBuilder."<init>":()V
   40:  astore_2

   // [snip a few lines for initializing the loop]
   // Loading the StringBuilder inside the loop, then append:
   66:  aload_2
   67:  aload   4
   69:  invokevirtual   #14; //Method Java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   72:  pop
   73:  aload_2
   74:  ldc #15; //String \t
   76:  invokevirtual   #14; //Method Java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   79:  pop

そのため、forループの内側は短く、繰り返しごとにStringBuilderをインスタンス化する必要がないため、実際には手動による最適化のほうがパフォーマンスが良くなります。

306
coobird

Java 8以降の場合

String listString = String.join(", ", list);

listがString型ではない場合は、結合コレクタを使用できます。

String listString = list.stream().map(Object::toString)
                        .collect(Collectors.joining(", "));
745

あなたがAndroid上でこれをしているのなら、.join(String delimiter, Iterable)メソッドを持っている TextUtils と呼ばれるこれのための素晴らしいユーティリティがあります。

List<String> list = new ArrayList<String>();
list.add("Item 1");
list.add("Item 2");
String joined = TextUtils.join(", ", list);

明らかにAndroidの外ではあまり使用されていませんが、私はこのスレッドに追加したいと考えました...

373
JJ Geewax

Apache Commons Langをダウンロードしてメソッドを使用してください。

 StringUtils.join(list)

 StringUtils.join(list, ", ") // 2nd param is the separator.

もちろん自分で実装することもできますが、それらのコードは十分にテストされており、おそらく最も可能性の高い実装です。

私はApache Commonsライブラリの大ファンであり、またそれはJava Standard Libraryへの素晴らしい追加であると思います。

215
Ravi Wallau

これはかなり古い質問ですが、私はもっと現代的な答えを追加することをお勧めします - GuavaJoiner クラスを使用します。

String joined = Joiner.on("\t").join(list);
137
Jon Skeet

List を読みやすく意味のある String に変更することは、本当によくある質問です。

ケース1 。クラスパスにApacheのStringUtilsがある場合(rogerdpackとRavi Wallauから)

import org.Apache.commons.lang3.StringUtils;
String str = StringUtils.join(myList);

ケース2 。 JDK(7)の方法を使いたいだけなら:

import Java.util.Arrays;
String str = Arrays.toString(myList.toArray()); 

自分で車輪を作ることは絶対にしないでください。この1行の作業にはループを使用しないでください。

77
Sheng.W

Java 5以降でクイックワンライナーを探しているなら、これを行うことができます。

myList.toString().replaceAll("\\[|\\]", "").replaceAll(", ","\t")

さらに、あなたの目的が単に内容を印刷することであり、 "\ t"についてあまり心配していないのであれば、あなたは単にこれをすることができます:

myList.toString()

これはのような文字列を返します

[str1、str2、str3]

(ArrayListではなく)Arrayがある場合は、次のように同じことを実行できます。

 Arrays.toString(myList).replaceAll("\\[|\\]", "").replaceAll(", ","\t")
56
Ken Shih

それをループしてtoStringを呼び出してください。魔法のような方法はありません、そして、もしあれば、それをループする以外に、カバーの下で何をしていると思いますか?唯一のマイクロ最適化については、Stringの代わりにStringBuilderを使用することであり、それでも大したことではありません。

StringBuilder out = new StringBuilder();
for (Object o : list)
{
  out.append(o.toString());
  out.append("\t");
}
return out.toString();
38
Paul Tomblin

ほとんどのJavaプロジェクトではApache-commons langが利用可能です。 StringUtils.join()メソッドはとても素敵で、ほとんどすべてのニーズを満たすためにいくつかの種類があります。

public static Java.lang.String join(Java.util.Collection collection,
                                    char separator)


public static String join(Iterator iterator, String separator) {
    // handle null, zero and one elements before building a buffer 
    Object first = iterator.next();
    if (!iterator.hasNext()) {
        return ObjectUtils.toString(first);
    }
    // two or more elements 
    StringBuffer buf = 
        new StringBuffer(256); // Java default is 16, probably too small 
    if (first != null) {
        buf.append(first);
    }
    while (iterator.hasNext()) {
        if (separator != null) {
            buf.append(separator);
        }
        Object obj = iterator.next();
        if (obj != null) {
            buf.append(obj);
        }
    }
    return buf.toString();
}

パラメーター:

collection - 結合する値のコレクション。nullの場合もある

separator - 使用する区切り文字

戻り値 :結合されたString、nullイテレータ入力の場合はnull

から:2.3

36
Brian

AndroidにはTextUtilクラスがあります - http://developer.Android.com/reference/Android/text/TextUtils.html

String implode = TextUtils.join("\t", list);
15
kehers

末尾の分離文字を扱う上品な方法は Class Separator を使うことです。

StringBuilder buf = new StringBuilder();
Separator sep = new Separator("\t");
for (String each: list) buf.append(sep).append(each);
String s = buf.toString();

Class SeparatorのtoStringメソッドは、最初の呼び出しで区切り文字exceptを返します。したがって、末尾の(この場合は)先頭の区切り文字なしでリストを印刷します。

13
akuhn

この単純なユースケースでは、単純に文字列をカンマで結合できます。 Java 8を使用している場合

String csv = String.join("\t", yourArray);

そうでなければcommons-langにjoin()メソッドがあります。

String csv = org.Apache.commons.lang3.StringUtils.join(yourArray, "\t");
12
Khader M A

ArrayListクラス( Java Docs )はAbstractListクラスを拡張し、これはtoString()メソッドを含むAbstractCollectionクラスを拡張します( Java Docs )。だからあなたは単に書く

listName.toString();

Java開発者はすでに最も効率的な方法を考え出し、きちんとパッケージ化され文書化された方法であなたにそれを与えました。そのメソッドを呼び出すだけです。

7
golddove

これはどちらの方法でもO(n)アルゴリズムです(リストを複数のサブリストに分割するマルチスレッドソリューションを使用した場合を除きますが、それが求めているものではないと思います)。

以下のようにStringBuilderを使うだけです。

StringBuilder sb = new StringBuilder();

for (Object obj : list) {
  sb.append(obj.toString());
  sb.append("\t");
}

String finalString = sb.toString();

各連結でStringBuilderオブジェクトを再インスタンス化することはないので、Stringは文字列連結よりはるかに高速になります。

6
Mike C.

Androidを使用していて、まだJackを使用していない場合(たとえば、Instant Runがまだサポートされていないため)、および結果の文字列の書式設定をさらに制御したい場合(たとえば、改行文字を(Java 7またはそれ以前のバージョンのコンパイラでストリームを使用するために)StreamSupportライブラリを使用したい/使用したい場合は、次のように使用できます(このメソッドを私のListUtilsクラスに入れました)。

public static <T> String asString(List<T> list) {
    return StreamSupport.stream(list)
            .map(Object::toString)
            .collect(Collectors.joining("\n"));
}

そしてもちろん、あなたのリストオブジェクトのクラスにtoString()を必ず実装してください。

5

次は何か良いことでしょう:

List<String> streamValues = new ArrayList<>();
Arrays.deepToString(streamValues.toArray()));   
3
Beezer

最後の要素の後に最後の\ tを付けたくない場合は、インデックスを使ってチェックする必要がありますが、listsがRandomAccessを実装している場合、これは「うまくいく」(つまりO(n))ことに注意してください。

List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

StringBuilder sb = new StringBuilder(list.size() * apprAvg); // every apprAvg > 1 is better than none
for (int i = 0; i < list.size(); i++) {
    sb.append(list.get(i));
    if (i < list.size() - 1) {
        sb.append("\t");
    }
}
System.out.println(sb.toString());
3
So So
List<String> stringList = getMyListOfStrings();
StringJoiner sj = new StringJoiner(" ");
stringList.stream().forEach(e -> sj.add(e));
String spaceSeparated = sj.toString()

セパレータとして使用したいcharシーケンスをnew StringJoinerに渡します。あなたがCSVをしたい場合:new StringJoiner(", ");

3
fmsf

以下のコードはあなたを助けるかもしれません、

List list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
String str = list.toString();
System.out.println("Step-1 : " + str);
str = str.replaceAll("[\\[\\]]", "");
System.out.println("Step-2 : " + str);

出力:

Step-1 : [1, 2, 3]
Step-2 : 1, 2, 3
3
Srinivasan.S

最善の方法ではないかもしれませんが、エレガントな方法です。

Arrays.deepToString(Arrays.asList( "Test"、 "Test2")

import Java.util.Arrays;

    public class Test {
        public static void main(String[] args) {
            System.out.println(Arrays.deepToString(Arrays.asList("Test", "Test2").toArray()));
        }
    }

出力

[テスト、テスト2]

3

Eclipse Collections を使用している場合は、makeString()メソッドを使用できます。

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

Assert.assertEquals(
    "one\ttwo\tthree",
    ArrayListAdapter.adapt(list).makeString("\t"));

ArrayListFastListに変換できれば、アダプタを取り除くことができます。

Assert.assertEquals(
    "one\ttwo\tthree",
    FastList.newListWith("one", "two", "three").makeString("\t"));

注:私はEclipseコレクションのコミッターです。

3
Craig P. Motlin

Java 8ではそれは簡単です。整数のリストについては、例を参照してください。

String result = Arrays.asList(1,2,3).stream().map(Object::toString).reduce((t, u) -> t + "\t" + u).orElse("");

または複数行バージョン(読みやすい):

String result = Arrays.asList(1,2,3).stream()
    .map(Object::toString)
    .reduce((t, u) -> t + "\t" + u)
    .orElse("");
2
amra

私は追加のリソースに依存する例をいくつか見ていますが、これが最も単純な解決策になるようです。 。

    List<Account> accounts = new ArrayList<>();

   public String accountList() 
   {
      Account[] listingArray = accounts.toArray(new Account[accounts.size()]);
      String listingString = Arrays.toString(listingArray);
      return listingString;
   }
1
Elliander

println を使用する代わりにタブを使用して区切るには、 print を使用できます。

ArrayList<String> mylist = new ArrayList<String>();

mylist.add("C Programming");
mylist.add("Java");
mylist.add("C++");
mylist.add("Perl");
mylist.add("Python");

for (String each : mylist)
{       
    System.out.print(each);
    System.out.print("\t");
}
1
chopss

一行で:[12,0,1,78,12]から12 0 1 78 12まで

String srt= list.toString().replaceAll("\\[|\\]|,","");
0

これは今ではかなり古い会話であり、Apache commonsは現在StringBuilderを内部的に使用しています。 http://commons.Apache.org/lang/api/src-html/org/Apache/commons/lang/StringUtils.html# line.3045

これでパフォーマンスは向上しますが、パフォーマンスが重要な場合は、使用する方法がやや非効率的になる可能性があります。インターフェースは柔軟であり、異なるCollection型間で一貫した振る舞いを可能にしますが、リストにとってはやや非効率的です。これは元の質問ではCollection型です。

これを基本としているのは、従来のforループで要素を単純に反復処理することで回避できるオーバーヘッドが発生するためです。代わりに、同時変更やメソッド呼び出しなどをチェックするシーンの背後でいくつかの追加の事柄が発生します。一方、イテレータがIterableオブジェクト(List)に対して使用されるため、拡張forループでは同じオーバーヘッドが発生します。

0
Alex VI

これには正規表現を使うことができます。これはそれが得るのと同じくらい簡潔です

System.out.println(yourArrayList.toString().replaceAll("\\[|\\]|[,][ ]","\t"));
0
Vikrant Goel