web-dev-qa-db-ja.com

Set <String>の内容を単語を空白で区切った単一の文字列に入れる最も速い方法は?

私はいくつかを持っています Set<String>sおよびこれらをそれぞれ単一のStringに変換します。元のSetの各要素は空白「」で区切られます。素朴な最初のアプローチは、このようにしています

Set<String> set_1;
Set<String> set_2;

StringBuilder builder = new StringBuilder();
for (String str : set_1) {
  builder.append(str).append(" ");
}

this.string_1 = builder.toString();

builder = new StringBuilder();
for (String str : set_2) {
  builder.append(str).append(" ");
}

this.string_2 = builder.toString();

誰もがこれを行うためのより速く、きれいな、またはより効率的な方法を考えることができますか?

49
Lars Andren

Commons/langでは、 StringUtils.join を使用してこれを行うことができます。

_String str_1 = StringUtils.join(set_1, " ");
_

簡潔にするために、本当にそれを打ち負かすことはできません。

更新:

この答えを読み直して、私は グアバのジョイナーに関する他の答え を好むでしょう。実際、最近では、Apacheコモンズの近くには行きません。

別の更新:

Java 8はメソッド String.join() を導入しました

_String joined = String.join(",", set);
_

これはGuavaバージョンほど柔軟ではありませんが、クラスパスにGuavaライブラリがない場合に便利です。

96

Java 8を使用している場合は、 native

String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)

方法:

指定された区切り文字のコピーで結合されたString要素のコピーで構成される新しいCharSequenceを返します。例えば:

 Set<String> strings = new LinkedHashSet<>();
 strings.add("Java"); strings.add("is");
 strings.add("very"); strings.add("cool");
 String message = String.join("-", strings);
 //message returned is: "Java-is-very-cool"

SetIterableを実装するため、単純に以下を使用します。

String.join(" ", set_1);
29
Jasper de Vries

Seanizerのcommons-langの答えの対比として、Googleの Guava Libraries (これはcommons-langの「後継者」と考えられます)を使用している場合は、 Joiner

Joiner.on(" ").join(set_1);

次のようなことを行うためのいくつかのヘルパーメソッドの利点:

Joiner.on(" ").skipNulls().join(set_1);
// If 2nd item was null, would produce "1, 3"

または

Joiner.on(" ").useForNull("<unknown>").join(set_1);
// If 2nd item was null, would produce "1, <unknown>, 3"

また、StringBuildersおよびWritersへの直接追加、およびその他のそのような機能もサポートしています。

20
Cowan

StringUtilライブラリを使用できないので(これ以上の選択肢はありません)、標準Javaを使用してこれを思いつきました。.

セットデータにカンマや角かっこが含まれていないことに確信がある場合は、次のように使用できます。

mySet.toString().replaceAll("\\[|\\]","").replaceAll(","," ");

「a」、「b」、「c」のセットは、.toString()を介して文字列「[a、b、c]」に変換されます。

次に、必要に応じて余分な句読点を置き換えます。

汚い。

6
user2808054

たぶんより短い解決策:

public String test78 (Set<String> set) {
    return set
        .stream()
        .collect(Collectors.joining(" "));
}

または

public String test77 (Set<String> set) {
    return set
        .stream()
        .reduce("", (a,b)->(a + " " + b));
}

しかし、ネイティブ、間違いなく高速

public String test76 (Set<String> set) {
    return String.join(" ", set);
}
4

私はこの方法を使用します:

public static String join(Set<String> set, String sep) {
    String result = null;
    if(set != null) {
        StringBuilder sb = new StringBuilder();
        Iterator<String> it = set.iterator();
        if(it.hasNext()) {
            sb.append(it.next());
        }
        while(it.hasNext()) {
            sb.append(sep).append(it.next());
        }
        result = sb.toString();
    }
    return result;
}
4
tuxdna

私はコードの複製について混乱しています。なぜそれを1つのセットを取り、1つの文字列を返す関数に含めるのでしょうか。

それ以外に、期待される容量についてのヒントを文字列ビルダーに与えることを除いて、あなたができることがたくさんあるかどうかはわかりません(設定サイズと文字列の長さの合理的な期待に基づいて計算できる場合)。

このためのライブラリ関数もありますが、それらが大幅に効率的であるとは思いません。

2
Uri

これは、セットからストリームを作成し、次に示すように、reduce操作を使用して要素を結合することで実行できます(Java 8ストリームチェック here の詳細について):

Optional<String> joinedString = set1.stream().reduce(new 
BinaryOperator<String>() {

     @Override
     public String apply(String t, String u) {

       return t + " " + u;
    }
});
return joinedString.orElse("");
2
Ehab Qadah