2016-01-22 7 views
7

を使用するstream.collect(Collectors.joining(", "))を使用すると、ストリームのすべての文字列をカンマで区切って簡単に追加できます。可能な結果は"a, b, c"です。しかし、もし私が最後の区切り文字を異なるものにしたいのであればどうでしょうか?例えば、結果として"a, b and c"が得られるように、" and "になるようにしてください。簡単な解決法はありますか? stream.collect(Collectors.joining(", "))最後の区切り文字が異なる文字列を結合する

+3

正直に言うと - いいえ、ありません。 'Collectors.joining'は、このようなことをしようとすると完全に分解するかなり面倒なトリックを使います。 –

+1

独自の['Collector'](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collector.html)を実装してください。 「簡単」に関しては、それは技術と意見の問題です。 – Andreas

+0

@Andreasこのようなコレクターを実装することは可能ですか?コレクタは特別な区切り文字をいつ使用するのかを知っていますか? –

答えて

1

は、残りのすべての文字列と、あなたの質問に使用されるコードを使用して、この新しい文字列に参加その後stream.collect(Collectors.joining(" and "))

で最初の最後の2列に参加してみます。

4

すでにリストに入っている場合、ストリームは必要ありません。単純にすべてのサブリストが、最後の要素に参加して、他の区切り文字と最後の要素をCONCAT:

int last = list.size() - 1; 
String joined = String.join(" and ", 
        String.join(", ", list.subList(0, last)), 
        list.get(last)); 

ここCollectors.collectingAndThen:

stream.collect(Collectors.collectingAndThen(Collectors.toList(), 
    joiningLastDelimiter(", ", " and "))); 

public static Function<List<String>, String> joiningLastDelimiter(
     String delimiter, String lastDelimiter) { 
    return list -> { 
       int last = list.size() - 1; 
       if (last < 1) return String.join(delimiter, list); 
       return String.join(lastDelimiter, 
        String.join(delimiter, list.subList(0, last)), 
        list.get(last)); 
      }; 
} 

を使用して、上記のこのバージョンはまた、ケースを扱うことができないバージョンがありますストリームが空であるか、値が1つしかない場合。 HolgerとAndreasのおかげで、このソリューションが大幅に改善されました。

私はオックスフォードのカンマが区切り文字として", "", and"を使用してこれを達成することができることをコメントで示唆していたが、それは二つの要素のための"a, and b"の誤った結果が得られ、その楽しみのためだけにここに正しくオックスフォードカンマがないものがあります:

stream.collect(Collectors.collectingAndThen(Collectors.toList(), 
    joiningOxfordComma())); 

public static Function<List<String>, String> joiningOxfordComma() { 
    return list -> { 
       int last = list.size() - 1; 
       if (last < 1) return String.join("", list); 
       if (last == 1) return String.join(" and ", list); 
       return String.join(", and ", 
        String.join(", ", list.subList(0, last)), 
        list.get(last)); 
      }; 
} 
+0

また、これをEclipseに貼り付け、コンパイルエラーが発生しました。これは、明示的に型を指定することで修正できます: 'Collector。<、String> of( ' – Andreas

+1

' javac'はコンパイルエラーを表示しませんが、明示的な型を追加することができますどのEclipseのバージョンですか? –

+2

ここから唯一の関連関数は*フィニッシャ*、あなたは単に 'Collectors.collectingAndThen(Collectors.toList()、list - > {...})'を使うこともできます。 – Holger

-1
String str = "a , b , c , d"; 
String what_you_want = str.substring(0, str.lastIndexOf(",")) 
     + str.substring(str.lastIndexOf(",")).replace(",", "and"); 

// what_you_want is : a , b , c and d 
4

あなたは"a, b, and c"と罰金であれば、それは追加の操作で、標準のストリームAPIを拡張して、私のStreamExライブラリのmapLast方法を使用することも可能です:

String result = StreamEx.of("a", "b", "c") 
         .mapLast("and "::concat) 
         .joining(", "); // "a, b, and c" 

mapLast方法は変わらず他人を保ち、最後のストリーム要素へのマッピングを与えられ適用されます。私も同じようなものがありますunit-test

+0

これはOPが望む答えではありませんが、あなたがオックスフォードカンマのファンであれば、この答えは文法的に「もっと」正しいものになります(返信文の場合は、(0、最後))、list.get(last)) 'ありがとうTagir。 –

1

古いJavaソリューションをお探しの場合は、Guava librariesを使用すると簡単です。

List<String> values = Arrays.asList("a", "b", "c"); 
    String output = Joiner.on(",").join(values); 
    output = output.substring(0, output.lastIndexOf(","))+" and "+values.get(values.size()-1); 
    System.out.println(output);//a,b and c 
0
List<String> names = Arrays.asList("Thomas", "Pierre", "Yussef", "Rick"); 
    int length = names.size(); 
    String result = IntStream.range(0, length - 1).mapToObj(i -> { 
     if (i == length - 2) { 
      return names.get(i) + " and " + names.get(length - 1); 
     } else { 
      return names.get(i); 
     } 
    }).collect(Collectors.joining(", ")); 
関連する問題