文字列として完全に出力したいArrayList
があります。基本的にはタブで区切られた各要素のtoString
を使って順番に出力したいです。これを行うための迅速な方法はありますか?それをループして(あるいは各要素を削除して)Stringに連結することもできますが、これは非常に遅いと思います。
基本的に、ループを使用して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
をインスタンス化する必要がないため、実際には手動による最適化のほうがパフォーマンスが良くなります。
Java 8以降の場合
String listString = String.join(", ", list);
list
がString型ではない場合は、結合コレクタを使用できます。
String listString = list.stream().map(Object::toString)
.collect(Collectors.joining(", "));
あなたが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の外ではあまり使用されていませんが、私はこのスレッドに追加したいと考えました...
Apache Commons Langをダウンロードしてメソッドを使用してください。
StringUtils.join(list)
StringUtils.join(list, ", ") // 2nd param is the separator.
もちろん自分で実装することもできますが、それらのコードは十分にテストされており、おそらく最も可能性の高い実装です。
私はApache Commonsライブラリの大ファンであり、またそれはJava Standard Libraryへの素晴らしい追加であると思います。
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行の作業にはループを使用しないでください。
Java 5以降でクイックワンライナーを探しているなら、これを行うことができます。
myList.toString().replaceAll("\\[|\\]", "").replaceAll(", ","\t")
さらに、あなたの目的が単に内容を印刷することであり、 "\ t"についてあまり心配していないのであれば、あなたは単にこれをすることができます:
myList.toString()
これはのような文字列を返します
[str1、str2、str3]
(ArrayListではなく)Arrayがある場合は、次のように同じことを実行できます。
Arrays.toString(myList).replaceAll("\\[|\\]", "").replaceAll(", ","\t")
それをループしてtoStringを呼び出してください。魔法のような方法はありません、そして、もしあれば、それをループする以外に、カバーの下で何をしていると思いますか?唯一のマイクロ最適化については、Stringの代わりにStringBuilderを使用することであり、それでも大したことではありません。
StringBuilder out = new StringBuilder();
for (Object o : list)
{
out.append(o.toString());
out.append("\t");
}
return out.toString();
ほとんどの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
AndroidにはTextUtilクラスがあります - http://developer.Android.com/reference/Android/text/TextUtils.html
String implode = TextUtils.join("\t", list);
末尾の分離文字を扱う上品な方法は 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を返します。したがって、末尾の(この場合は)先頭の区切り文字なしでリストを印刷します。
この単純なユースケースでは、単純に文字列をカンマで結合できます。 Java 8を使用している場合
String csv = String.join("\t", yourArray);
そうでなければcommons-langにjoin()メソッドがあります。
String csv = org.Apache.commons.lang3.StringUtils.join(yourArray, "\t");
これはどちらの方法でもO(n)
アルゴリズムです(リストを複数のサブリストに分割するマルチスレッドソリューションを使用した場合を除きますが、それが求めているものではないと思います)。
以下のようにStringBuilder
を使うだけです。
StringBuilder sb = new StringBuilder();
for (Object obj : list) {
sb.append(obj.toString());
sb.append("\t");
}
String finalString = sb.toString();
各連結でStringBuilder
オブジェクトを再インスタンス化することはないので、String
は文字列連結よりはるかに高速になります。
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()を必ず実装してください。
次は何か良いことでしょう:
List<String> streamValues = new ArrayList<>();
Arrays.deepToString(streamValues.toArray()));
最後の要素の後に最後の\ 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());
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(", ");
以下のコードはあなたを助けるかもしれません、
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
最善の方法ではないかもしれませんが、エレガントな方法です。
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]
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"));
ArrayList
をFastList
に変換できれば、アダプタを取り除くことができます。
Assert.assertEquals(
"one\ttwo\tthree",
FastList.newListWith("one", "two", "three").makeString("\t"));
注:私はEclipseコレクションのコミッターです。
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("");
私は追加のリソースに依存する例をいくつか見ていますが、これが最も単純な解決策になるようです。 。
List<Account> accounts = new ArrayList<>();
public String accountList()
{
Account[] listingArray = accounts.toArray(new Account[accounts.size()]);
String listingString = Arrays.toString(listingArray);
return listingString;
}
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");
}
一行で:[12,0,1,78,12]から12 0 1 78 12まで
String srt= list.toString().replaceAll("\\[|\\]|,","");
これは今ではかなり古い会話であり、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ループでは同じオーバーヘッドが発生します。
これには正規表現を使うことができます。これはそれが得るのと同じくらい簡潔です
System.out.println(yourArrayList.toString().replaceAll("\\[|\\]|[,][ ]","\t"));