私が持っているArrayList
、私は完全に文字列として出力したいということ。基本的にtoString
、タブで区切られた各要素のを使用して順に出力したいと思います。これを行う高速な方法はありますか?あなたはそれをループして(または各要素を削除して)文字列に連結することができますが、これは非常に遅くなると思います。
私が持っているArrayList
、私は完全に文字列として出力したいということ。基本的にtoString
、タブで区切られた各要素のを使用して順に出力したいと思います。これを行う高速な方法はありますか?あなたはそれをループして(または各要素を削除して)文字列に連結することができますが、これは非常に遅くなると思います。
回答:
基本的に、ループを使用して反復処理すること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による応答です。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
またはGeewaxをAndroid
Java 8以降の場合:
String listString = String.join(", ", list);
がlist
String型でない場合は、結合コレクターを使用できます。
String listString = list.stream().map(Object::toString)
.collect(Collectors.joining(", "));
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以外ではあまり使用されていませんが、このスレッドに追加すると思いました...
TextUtils.join
とりObject[]
、私はそれを呼び出すことだと仮定したいtoString()
各トークンに。PatientDetails
実装toString()
?それでも問題が解決しない場合は、Separator
クラスで何かをすることに行き詰まっている可能性があります。
org.apache.lang3.StringUtils
事実上同じなので、あなたの答えはAndroid以外では私にとって非常
Apache Commons Langをダウンロードしてメソッドを使用する
StringUtils.join(list)
StringUtils.join(list, ", ") // 2nd param is the separator.
もちろん、自分で実装することもできますが、コードは完全にテストされており、おそらく最良の実装です。
私はApache Commonsライブラリの大ファンであり、Java標準ライブラリへのすばらしい追加でもあると思います。
StringUtils.join(list.toArray(),"\t")
これはかなり古い質問ですが、もっと現代的な答えを追加した方がよいと思います- グアバのJoiner
クラスを使用してください:
String joined = Joiner.on("\t").join(list);
リストを読みやすく意味のある文字列に変更することは、誰もが遭遇する可能性のあるよくある質問です。
ケース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行のタスクではループを使用しないでください。
Arrays.toString(myList.toArray())
-最も簡単で最も簡単なソリューション
Arrays.toString(list.toArray())
書くのは簡単ですが、非常に非効率的です。
Java 5以降、簡単なワンライナーを探していた場合は、次のようにしてください。
myList.toString().replaceAll("\\[|\\]", "").replaceAll(", ","\t")
さらに、目的がコンテンツを印刷することだけで、 "\ t"をあまり気にしない場合は、次のようにします。
myList.toString()
次のような文字列を返します
[str1、str2、str3]
ArrayListではなくArrayがある場合は、次のように同じことを実行できます。
Arrays.toString(myList).replaceAll("\\[|\\]", "").replaceAll(", ","\t")
m
世帯の人を検索するように言うと、またはと言いますが、「この国でこの人を探す」と言い換えれば、すぐにわかります。その上、ここでのすべてのアルゴリズムは一般にであり、ループ内にループはありません。n
x
O(mnx)
O(n^3)
O(n)
O(n)
ループしてtoStringを呼び出します。魔法の方法はありません。もしあったとしても、それをループする以外に、カバーの下で何をしていると思いますか?唯一のマイクロ最適化については、Stringの代わりにStringBuilderを使用することですが、それでも大したことではありません。文字列を連結すると、裏側で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-使用するセパレーター文字
戻り値:結合された文字列。イテレータ入力がnullの場合はnull
以降:2.3
join(...)
メソッドには配列とコレクションの両方のバリアントがあるため、これは非常に便利です。
末尾の分離文字を処理するエレガントな方法は、クラスセパレーターを使用することです。
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メソッドは、最初の呼び出しを除いて、セパレーターを返します。したがって、末尾(またはこの場合)の先行セパレータなしでリストを印刷します。
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"));
filter
。結局、コードを読むのがずっと簡単になりました。
String
も同様である場合にのみ機能します。Integer
sのリストに問題がある場合
これは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のサポートがまだ不足しているため)、結果の文字列のフォーマットをより詳細に制御したい場合(たとえば、改行文字を要素の仕切り)、そして偶然にStreamSupportライブラリを使用する/使用したい場合(Java 7以前のバージョンのコンパイラでストリームを使用する場合)、次のようなものを使用できます(このメソッドをListUtilsクラスに配置します)。
public static <T> String asString(List<T> list) {
return StreamSupport.stream(list)
.map(Object::toString)
.collect(Collectors.joining("\n"));
}
そしてもちろん、リストオブジェクトのクラスに必ずtoString()を実装してください。
reduce
文字列連結では、使用は非常に非効率的です。return StreamSupport.stream(list).map(Object::toString).collect(joining("\n"))
内部的に使用するJava 8の方法で行う必要がありますStringJoiner
。streamsupportでもこれを実行できなかった理由はありません。
Optional#get
、空のリストが渡されると、コードが(が原因で)ひどく失敗することです。
最後の要素の後の最後の\ 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());
最善の方法ではないかもしれませんが、エレガントな方法です。
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のコレクションを、あなたが使用することができる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コレクションのコミッターです。
1行で:[12,0,1,78,12]から12 0 1 78 12
String srt= list.toString().replaceAll("\\[|\\]|,","");
追加のリソースに依存するかなりの例が表示されますが、これは最も簡単な解決策のようです(これは私が自分のプロジェクトで使用したものです)。これは基本的に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;
}
これは今ではかなり古い会話であり、Apache Commonsは現在、StringBuilderを内部的に使用しています:http : //commons.apache.org/lang/api/src-html/org/apache/commons/lang/StringUtils.html#line。 3045
これにより、パフォーマンスが向上しますが、パフォーマンスが重要な場合は、使用する方法が多少非効率になる可能性があります。インターフェースは柔軟性があり、さまざまなコレクションタイプ間で一貫した動作を可能にしますが、元の質問のコレクションのタイプであるリストでは、いくらか非効率的です。
これは、従来のforループの要素を単純に反復することで回避できるオーバーヘッドが発生することに基づいています。代わりに、同時変更やメソッド呼び出しなどをチェックする舞台裏でいくつかの追加の処理が行われます。一方、イテレータがIterableオブジェクト(リスト)で使用されるため、拡張forループは同じオーバーヘッドをもたらします。
この関数はどうですか:
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();
}
それはあらゆるタイプのコレクションで機能します...