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


353

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


4
または各要素を削除します。「ループ」は要素の移動により2次時間がかかるため(最初の要素から最後の要素にループする場合)、注意してください。
Dimitry K

回答:


329

基本的に、ループを使用して反復処理すること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と、おそらくパフォーマンスが向上します。)

実際、あらゆる種類の出力(ディスクへの出力でも画面への出力でも)は、文字列連結のパフォーマンスを心配する必要がある場合よりも、少なくとも1桁遅いと思います。

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

ループの外側で単一のオブジェクトをインスタンス化するだけなので、使用する最も最適化された手法はPaul Tomblinによる応答です。StringBuilderfor

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

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反復ごとにをインスタンス化する必要がないため、実際に手の最適化の方が優れているはずです。


8
パフォーマンス上の理由から、単に文字列を追加するのではなく、StringBuilderクラスの使用を検討してください。
ジェレミー

5
コンパイラは文字列の連結を最適化しますが、ループが実行されるたびに新しいStringBuilderオブジェクトを作成します。
ペドロエンリケス

4
+ =を使用する場合は-1。この場合、パフォーマンスが向上します。文字列に繰り返し追加する場合は、常にStringBuilderを使用します。
starblue

10
このソリューションは、特にコンマ区切りのリストなどを作成する場合に、文字列の末尾に余分な「\ t」を追加します。ここに掲載されている他のソリューションは、Apache CommonsまたはGuavaを使用した方が優れていると思います。
Peter Goetz 2012

3
これは最良の答えではありません。以下のVitalii JavaまたはGeewaxをAndroid
ご覧ください

895

Java 8以降の場合:

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

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

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

144
これを追加するのにJava 8が必要だったとは思えません。
ポール

45
この回答はもっと賛成投票する必要があります!ハック、ライブラリ、ループはありません。
Songo 2014

4
これはOPが言ったことに対しては機能しません。String.joinは2番目の引数としてIterable <?CharSequence>を拡張します。そのため、表示するList <String>がある場合は機能しますが、List <MyObject>がある場合は、OPで必要なtoString()を呼び出しません
Hilikus

3
なぜこれが最初の(そして受け入れられた)答えではないのですか?。そこにあることがわかるまで、常に下にスクロールする必要があります..エレガントで簡潔
Jack

2
Android API 26+が必要
Arsen Sench 2017

391

Androidでこれを実行している場合は、TextUtilsと呼ばれる、.join(String delimiter, Iterable)メソッドを持つ便利なユーティリティがあります。

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

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


1
以来TextUtils.joinとりObject[]、私はそれを呼び出すことだと仮定したいtoString()各トークンに。PatientDetails実装toString()?それでも問題が解決しない場合は、Separatorクラスで何かをすることに行き詰まっている可能性があります。
JJ Geewax 2012年

5
org.apache.lang3.StringUtils事実上同じなので、あなたの答えはAndroid以外では私にとって非常
Patrick

1
この回答の人気(現在最高の投票数)は、Javaの質問の多くがAndroid開発に起因していることを示しています
Amr H. Abd Elmajeed

1
私の問題を解決するためにあなたがこの地球に送られたに
違い

1
あなたは私の命を救いました。<3
Pratik Butani

234

Apache Commons Langをダウンロードしてメソッドを使用する

 StringUtils.join(list)

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

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

私はApache Commonsライブラリの大ファンであり、Java標準ライブラリへのすばらしい追加でもあると思います。


63
残念ながら、SOの住人は車輪を再発明することを好みます。
skaffman 2009

33
Apache Commons Langにもあります。使用法は次のようになりますStringUtils.join(list.toArray(),"\t")
Muhd

33
この特定のホイールは、追加の依存関係の価値はほとんどありません。
セヴァAlekseyev

25
@SevaAlekseyev私はそれが議論の余地があると思います。この依存関係をすぐに追加すると、そのクラスを頻繁に使用するようになります。「if string!= null && string.trim()!= "」を使用する代わりに、StringUtils.isNotEmpty ...を使用します。ObjectUtils.equals()を使用すると、どこでもnullを確認する必要がなくなります。しかし、これらのライブラリを使用することを正当化する1つの依存関係を待つと、実際にそれらを使用することはない可能性があります
Ravi Wallau

6
また、最後にタブが追加されないのもいいですね。
keuleJ

139

これはかなり古い質問ですが、もっと現代的な答えを追加した方がよいと思います- グアバJoinerクラスを使用してください:

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

2
これが私のお気に入りのソリューションです。:->グアバの+1。
csgeek 2014

グアバの場合もCtrl + Fを押します。ありがとう!
Priidu Neemre 2015

List <String>リスト=新しいArrayList <String>(); list.add( "Hello"); list.add( "Hai"); list.add( "Hi"); System.out.println(list.toString()。substring(1、list.toString()。length()-1).replaceAll( "、"、 "\ t"));
Lova Chittumuri

86

リストを読みやすく意味のある文字列に変更することは、誰もが遭遇する可能性のあるよくある質問です。

ケース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行のタスクではループを使用しないでください。


1
私は自分のケース2の解決策に気づかなかったので、自分で解決策を投稿しました。あなたのものは実際にははるかに優れており、余分なステップを節約できます。追加のツールが必要と思われるいくつかの回答よりも間違いなくお勧めします。
Elliander 2015

5
Arrays.toString(myList.toArray())-最も簡単で最も簡単なソリューション
Ondrej Bozek

私はこれが最善かつ最も効率的なソリューションと考えられるべきだと思います
Morey

Arrays.toString(list.toArray())書くのは簡単ですが、非常に非効率的です。
Matthieu

60

Java 5以降、簡単なワンライナーを探していた場合は、次のようにしてください。

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

さらに、目的がコンテンツを印刷することだけで、 "\ t"をあまり気にしない場合は、次のようにします。

myList.toString()

次のような文字列を返します

[str1、str2、str3]

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

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

3
これは実際には上記の方法よりも効率的だと思います。それは底に示されているそのような残念。エレガントではないかもしれませんが、私はあなたの解決策がO(n)を実行する一方で、他の理論的にはO(n ^ 2)で実行されると強く信じています(Java文字列は不変なので、基本的にすべてのマージで新しい文字列を作成し、結果の文字列が大きくなります)
user3790827

テキストが非常に大きい場合は、コンピュータのリソースを浪費してしまいます。
user3790827

このメソッドは、StringBuilderを使用する場合よりも7〜8倍遅くなります。
Zoka 2016年

@ user3790827あなたは非常に表面的なレベルを見ています。州の都市にあるm世帯の人を検索するように言うと、またはと言いますが、「この国でこの人を探す」と言い換えれば、すぐにわかります。その上、ここでのすべてのアルゴリズムは一般にであり、ループにループはありません。nxO(mnx)O(n^3)O(n)O(n)
Jai

39

ループしてtoStringを呼び出します。魔法の方法はありません。もしあったとしても、それをループする以外に、カバーの下で何をしていると思いますか?唯一のマイクロ最適化については、Stringの代わりにStringBuilderを使用することですが、それでも大したことではありません。文字列を連結すると、裏側でStringBuilderになりますが、少なくとも、このように記述すれば、何が起こっているかを確認できます。

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

ありがとう!これが私がやっていることです:)
Juan Besa

4
大きなアレイの場合、これは間違いなくマイクロ最適化ではありません。StringBuilderを使用する自動変換は、文字列の連結ごとに個別に行われますが、ループの場合は役に立ちません。多数の要素を1つの式に連結しても問題ありません。
starblue 2009年

1
連結している場合、StringBuilderを明示的に使用することは非常に重要です。たとえば、50 000個の文字列が1 MBの結果文字列を作成しているとします。1秒の実行時間と比べて1分の差になる場合があります。
Napik氏、2013

36

ほとんどの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-使用するセパレーター文字

戻り値:結合された文字列。イテレータ入力がnullの場合はnull

以降:2.3


2
join(...)メソッドには配列とコレクションの両方のバリアントがあるため、これは非常に便利です。
vikingsteve

要素がほとんど入力されない文字列のコレクションを、乱数で作成する必要がありました。最後に、配列ではなく配列ではなく文字列が必要でした。これは私のコードです:Collections.shuffle(L); StringBuilder sb = new StringBuilder(); L.forEach(e-> sb.append(e)); return sb.toString();
dobrivoje

18

Androidには、http: //developer.android.com/reference/android/text/TextUtils.htmlを使用できるTextUtilクラスがあります。

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

このソリューションは、API 26+を必要とするString.joinよりも優れています
Smith.Lai

14

この単純な使用例では、文字列をカンマで結合するだけです。Java 8を使用する場合:

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

それ以外の場合、commons-langにはjoin()メソッドがあります。

String csv = org.apache.commons.lang3.StringUtils.join(yourArray, "\t");

13

末尾の分離文字を処理するエレガントな方法は、クラスセパレーターを使用することです。

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メソッドは、最初の呼び出しを除いて、セパレーターを返します。したがって、末尾(またはこの場合)の先行セパレータなしでリストを印刷します。


8

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("");

更新-短いバージョン

String result = Arrays.asList(1,2,3).stream()
                .map(Object::toString)
                .collect(Collectors.joining("\t"));

2
これは一行のコードにすぎないかもしれませんが、私には簡単には見えません。私にとって、リストをトラバースし、その要素を文字列に解析することは、これよりも簡単です。
Bartzilla、2015年

1
これも第一印象でした。しかし、慣れてきたら、素晴らしいと思います。たとえば、のような操作を追加できますfilter。結局、コードを読むのがずっと簡単になりました。
amra

3
Java 8の場合:String.join( "\ t"、array)
Tomasz

最後のコメントは、コンテンツStringも同様である場合にのみ機能します。Integersのリストに問題がある場合
LeO

これら3つすべてで、AndroidのAPIレベル24が必要です。
Asad35Waheed

6

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

StringBuilder以下のように使用してください:

StringBuilder sb = new StringBuilder();

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

String finalString = sb.toString();

StringBuilderあなたが再インスタンス化されませんので、より高速な文字列の連結よりも多くなりString、各連結上のオブジェクト。


5

たまたまAndroidを使用していて、まだJackを使用していない場合(たとえば、Instant Runのサポートがまだ不足しているため)、結果の文字列のフォーマットをより詳細に制御したい場合(たとえば、改行文字を要素の仕切り)、そして偶然にStreamSupportライブラリを使用する/使用したい場合(Java 7以前のバージョンのコンパイラでストリームを使用する場合)、次のようなものを使用できます(このメソッドをListUtilsクラスに配置します)。

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

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


1
reduce文字列連結では、使用は非常に非効率的です。return StreamSupport.stream(list).map(Object::toString).collect(joining("\n"))内部的に使用するJava 8の方法で行う必要がありますStringJoinerstreamsupportでもこれを実行できなかった理由はありません。
Stefan Zobel

もう1つはOptional#get、空のリストが渡されると、コードが(が原因で)ひどく失敗することです。
Stefan Zobel 2016

@StefanZobel効率性とエッジケースの問題を指摘していただきありがとうございます。コードを修正しました。
Javad Sadeqzadeh 16

3

最後の要素の後の最後の\ tが不要な場合は、インデックスを使用して確認する必要がありますが、リストが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

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

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

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

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]


1
「最高」がコードの読みやすさを意味する場合、これが最良の方法だと思います。私はコードを見ていませんが、出力ではカスタマイズできませんが、おそらくStringBuilderメソッド(おそらく内部でStringBuilderを使用しています)と同じくらい効率的です。
Mike Miller

3

以下は良いでしょうか?

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

3

あなたが使用している場合はEclipseのコレクションを、あなたが使用することができる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
List<String> stringList = getMyListOfStrings();
StringJoiner sj = new StringJoiner(" ");
stringList.stream().forEach(e -> sj.add(e));
String spaceSeparated = sj.toString()

new StringJoinerセパレータとして使用する文字シーケンスを渡します。CSVを実行する場合:new StringJoiner(", ");


3

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

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

2
1)このようなコードを使用する理由はもうありません(4年前!)。2)この回答はQ&Aに何も追加しません。
Radiodef

1行に5つ星。どうもありがとう。
Atef Farouk、

これは完全に機能します。カンマ区切りの文字列を使用する場合:String srt = list.toString()。replaceAll( "\ [| \]"、 "");
Asad35Waheed

2

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

追加のリソースに依存するかなりの例が表示されますが、これは最も簡単な解決策のようです(これは私が自分のプロジェクトで使用したものです)。これは基本的にArrayListからArrayに変換し、次にListに変換するだけです。 。

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

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

0

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

これにより、パフォーマンスが向上しますが、パフォーマンスが重要な場合は、使用する方法が多少非効率になる可能性があります。インターフェースは柔軟性があり、さまざまなコレクションタイプ間で一貫した動作を可能にしますが、元の質問のコレクションのタイプであるリストでは、いくらか非効率的です。

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


0

これには正規表現を使用できます。これはできるだけ簡潔です

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

-1

この関数はどうですか:

public static String toString(final Collection<?> collection) {
    final StringBuilder sb = new StringBuilder("{");
    boolean isFirst = true;
    for (final Object object : collection) {
        if (!isFirst)
            sb.append(',');
        else
            isFirst = false;
        sb.append(object);
    }
    sb.append('}');
    return sb.toString();
}

それはあらゆるタイプのコレクションで機能します...

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