2017-11-14 2 views
0

私は2つのセット - 国と州を持っています。私は両方からすべての可能な順列を作成したいと思います。複数の設定値から文字列の順列を生成する(Java 8ストリーム)

import java.util.*; 
import java.util.stream.Collectors; 

public class HelloWorld{ 

public static void main(String []args){ 
    System.out.println("Hello World"); 

    Set<String> countryPermutations = new HashSet<>(Arrays.asList("United States of america", "USA")); 
    Set<String> statePermutations = new HashSet<>(Arrays.asList("Texas", "TX")); 

    Set<String> stateCountryPermutations = countryPermutations.stream() 
     .flatMap(country -> statePermutations.stream() 
       .flatMap(state -> Stream.of(state + country, country + state))) 
     .collect(Collectors.toSet()); 

    Set<String> finalAliases = Optional.ofNullable(stateCountryPermutations) 
      .map(Collection::stream).orElse(Stream.empty()) 
       .map(sc -> "houston " + sc) 
       .collect(Collectors.toSet()); 
    System.out.println(stateCountryPermutationAliases); 
} 
} 

州または国または両方の置換はnullでもかまいません。私はまだ私のコードが機能するようにしたい。

要件

  1. 状態の順列がnullの場合、最終的な出力があるべき[ヒューストンアメリカ、アメリカのヒューストン米国]

  2. 国の順列がnullの場合、最終的な出力があるべき[ヒューストンTX 、テキサス州ヒューストン]

  3. 両方がnullの場合は、出力なし

は私が1 & 2が満たされていない、以下

Set<String> stateCountryPermutations = 
    Optional.ofNullable(countryPermutations) 
      .map(Collection::stream) 
      .orElse(Stream.empty()) 
      .flatMap(country -> Optional.ofNullable(statePermutations) 
             .map(Collection::stream) 
             .orElse(Stream.empty()) 
             .flatMap(state -> Stream.of(state + country, country + state))) 
      .collect(Collectors.toSet()); 

これを満たす3.いずれかの順列がnullに私のコードを変更しています。私は応答として別名を取得しません。コードを変更するにはどうすればよいですか?

+0

私は最後のコードサンプルを試しましたが、どちらかまたは両方のセットがnull(または空)の場合、emtpy結果が得られます。つまり、3を満たすだけです。ストリーム、またはいくつかのカントリーストリームを空の**ストリームに、または**何も** **空の**ストリームに割り当てることができます。これを解決するには、「国なし」または「状態なし」のプレースホルダとしてnullオブジェクト(ヌル自体ではなく、空の文字列のようなもの)を導入できます。ストリームの前でチェックするだけで、入力セットを結果として使うことができます( '' if(countries == null)permutations = states; '')。 –

+0

ありがとう@MalteHartwig、私のポストを更新しました。 –

+0

簡単にするために、私は2つのセットを使用しました。私の実際のコードは4つのセットを通して順列変換が必要です。 if-elseがあまりにも厄介になる –

答えて

2

次のコードがnull /空集合を無視して、入力セットの任意の数のすべての組み合わせを作成します。

Stream<Collection<String>> inputs = Stream.of(Arrays.asList("United States of america", "USA"), 
               Arrays.asList("Texas", "TX"), 
               Arrays.asList("Hello", "World"), 
               null, 
               new ArrayList<>()); 

Stream<Collection<List<String>>> listified = inputs.filter(Objects::nonNull) 
                .filter(input -> !input.isEmpty()) 
                .map(l -> l.stream() 
                   .map(o -> new ArrayList<>(Arrays.asList(o))) 
                   .collect(Collectors.toList())); 

Collection<List<String>> combinations = listified.reduce((input1, input2) -> { 
    Collection<List<String>> merged = new ArrayList<>(); 
    input1.forEach(permutation1 -> input2.forEach(permutation2 -> { 
     List<String> combination = new ArrayList<>(); 
     combination.addAll(permutation1); 
     combination.addAll(permutation2); 
     merged.add(combination); 
    })); 
    return merged; 
}).orElse(new HashSet<>()); 

combinations.forEach(System.out::println); 

出力:

[United States of america, Texas, Hello] 
[United States of america, Texas, World] 
[United States of america, TX, Hello] 
[United States of america, TX, World] 
[USA, Texas, Hello] 
[USA, Texas, World] 
[USA, TX, Hello] 
[USA, TX, World] 

今あなたが作成するためにあなたの言及ヘルパーメソッドを使用することができます各組み合わせの順列。 This questionは、リストのすべての順列を生成する方法を示しています。あなたの質問を言い換えるする

+0

ここではたくさんの努力をしています... +1 – Eugene

1

は、私の知る限り理解されるように、あなたはすべてがnullであれば、空のストリームを生成する、のラベルそれらを呼び出すと、すべての非nullコレクションの順列を作成してみましょう、いくつかのコレクションを持っています。これはストレートフォワードロジックで行うことができます

、すべてのコレクション経由でストリーミング、null要素を除外し、Stream秒にそれらをマッピングし、ストリームがより多くを使用することができないことを除いて、streamA.stream().flatMap(… -> streamB.map(combiner))ロジックを使用して単一のストリームにそれらを減らします一度よりこれを解決するために、同じロジックをのサプライヤに適用することによって実装することができます。あなたの場合、.map(combiner)a -> streamB.flatMap(b -> Stream.of(combine a and b, combine b and a))になるはずです。

// testcases 
List<Collection<String>> countryLabelTestCases = Arrays.asList(
    Arrays.asList("United States of america", "USA"), 
    null 
); 
List<Collection<String>> stateLabelTestCases = Arrays.asList(
    Arrays.asList("Texas", "TX"), 
    null 
); 
for(Collection<String> countryLabels: countryLabelTestCases) { 
    for(Collection<String> stateLabels: stateLabelTestCases) { 
     // begin test case 
     System.out.println(" *** "+(
      countryLabels==null? stateLabels==null? "both null": "countryLabels null": 
           stateLabels==null? "stateLabels null": "neither null" 
      )+":" 
     ); 

     // actual operation: 

     Stream.of(stateLabels, countryLabels) 
       .filter(Objects::nonNull) 
       .<Supplier<Stream<String>>>map(c -> c::stream) 
       .reduce((s1,s2) ->() -> s1.get().flatMap(x -> 
             s2.get().flatMap(y -> Stream.of(x+" "+y, y+" "+x)))) 
       .orElse(Stream::empty) 
       .get() 
       .map("houston "::concat) 
       .forEach(System.out::println); 

     // end of operation 
     System.out.println(); 
    } 
} 
*** neither null: 
houston Texas United States of america 
houston United States of america Texas 
houston Texas USA 
houston USA Texas 
houston TX United States of america 
houston United States of america TX 
houston TX USA 
houston USA TX 

*** stateLabels null: 
houston United States of america 
houston USA 

*** countryLabels null: 
houston Texas 
houston TX 

*** both null: 

をあなたは、リストではなく文字列として並べ替えを取得し、このヘルパーメソッド

static <T> List<T> merge(List<T> a, List<T> b) { 
    return Stream.concat(a.stream(), b.stream()).collect(Collectors.toList()); 
} 

を作成し、変更したい場合は、次のテストケースを実証するために

Stream.of(stateLabels, countryLabels) // stream over all collections 
     .filter(Objects::nonNull)  // ignore all null elements 
     .<Supplier<Stream<String>>>map(c -> c::stream) // map to a supplier of stream 
     .reduce((s1,s2) -> // combine them using flatMap and creating a×b and b×a 
     () -> s1.get().flatMap(x -> s2.get().flatMap(y -> Stream.of(x+" "+y, y+" "+x)))) 
     .orElse(Stream::empty) // use supplier of empty stream when all null 
     .get() // get the resulting stream 
     .map("houston "::concat) // combine all elements with "houston " 
     .forEach(System.out::println); 

ストリーム操作から

Stream.of(stateLabels, countryLabels) 
     .filter(Objects::nonNull) 
     .<Supplier<Stream<List<String>>>>map(c -> 
     () -> c.stream().map(Collections::singletonList)) 
     .reduce((s1,s2) ->() -> s1.get().flatMap(x -> 
           s2.get().flatMap(y -> Stream.of(merge(x,y), merge(y,x))))) 
     .orElse(Stream::empty) 
     .get() 
     .map(list -> merge(Collections.singletonList("houston"), list)) 
     // proceed processing the List<String>s 

2つ以上のコレクションをサポートするには、Stream.of(stateLabels, countryLabels)を変更し、他のコレクションを挿入するだけでよいことに注意してください。

+0

こんにちは@Holgerありがとうございます。 reduce関数は2つ以上のストリームを組み込むためにどのように書き直さなければならないでしょうか? –

+0

何も書き換える必要はありません。 – Holger

+0

@PranavKapoorが何を望んでいるかによって1つの問題が発生する可能性があります:2つ以上のリストを使用する場合、マージ(マージ) a、b、c]、[c、a、b]、[b、a、c]になります。 、[c、b、a] 'であるが、前の組み合わせの途中で第3(および第4 ...)リストの要素を混ぜることはない。これは 'Stream.of(merge(x、y))'だけを減らし、その後の順列を思いつくことで対処できます。 [この質問](https://stackoverflow.com/questions/10305153/generating-all-possible-permutations-of-a-list-recursively)は、その方法を示しています。 –

関連する問題