2017-01-27 9 views
4

でEithersのリストを分割、私はHaskellのeitherhttps://hackage.haskell.org/package/base-4.9.1.0/docs/Data-Either.html)に触発され、JavaでEitherの私の独自の実装を試してい主に学術的な運動としてのJava

私は喜んでいる作業の実装を持っています:

Stream<String> s = streamOfEithers 
    .filter(Either::isLeft) 
    .map(x -> x.left()) 

Either<String, Integer> either = Either.left(A_STRING); 
    assertThat(either.left(), is(A_STRING)); 
    assertThat(either.isLeft(), is(true)); 
    assertThat(either.isRight(), is(false)); 
    assertThat(either.map(x -> AN_INTEGER, y -> A_LONG), is(Either.left(AN_INTEGER))); 
    assertThat(either.consolidate(x -> A_LONG, y -> ANOTHER_LONG), is(A_LONG)); 

Haskellのleftsの同等とrightsストリームをフィルタリングすることです

私が抱えている問題は、HaskellのpartitionEithersと同等のものを作成することです。

私の最初の本能た:

streamOfEithers.collect(Collectors.groupingBy(Either::isLeft)) 

しかし、これは私のタイプを失うようだ - それは、(例えば)Map<Boolean, Either<? extends Object, ? extends Object>>ではなく、Map<Boolean, Either<String,Integer>を返します。

もちろん、パーティション化の結果はEithersという2つのリストではなく、それぞれのタイプのリストが2つあります。 JavaはPair<T,U>クラスを持っていないが、それはしなかった場合は、おそらく:

List<Either<String,Integer>> listOfEithers = ... 
Pair<List<String>,List<Integer>> partitioned = Either.partitionList(listOfEithers); 

をそれ以外の場合は、私が管理している最高のは、次のとおりです。

Map<Boolean, Either<String,Integer>> partitioned = Either.partitionList(listOfEithers); 

...のために非常に便利な構造ではないいますクライアント。

Pairを書いて、またはいくつかのコレクションライブラリから Pairを使用するよりも他の

(グアバは、ちなみに、それは「良いよりも害を行います」とPairを提供することを拒否)、どのように私は最高のHaskellのpartitionEithersに相当するものを提供することができますか?

答えて

2

Pairの代わりに、具体的にEitherに合わせた独自の集約タイプを作成することができます。これにはコレクタが付いています。ここでは単純化された実装です:

class Aggregate<T, U> { 
    List<T> tList = new ArrayList<>(); 
    List<U> uList = new ArrayList<>(); 

    public void add(Either<T, U> e) { 
     if(e.isLeft()) { 
      tList.add(e.left()); 
     } else { 
      uList.add(e.right()); 
     } 
    } 

    public Aggregate<T, U> combine(Aggregate<T, U> other) { 
     tList.addAll(other.tList); 
     uList.addAll(other.uList); 
     return this; // could create a new Aggregate here instead... 
    } 

    public static <T, U> Collector<Either<T,U>, ? , Aggregate<T, U>> partitionEithers() { 
     return Collector.of(Aggregate::new, Aggregate::add, Aggregate::combine); 
    } 
} 

その後の結果は次のようになります。

Aggregate<String, Integer> result = streamOfEithers.collect(Aggregate.partitionEithers()); 
+0

- カスタムタイプが必要とされている - 私は 'PartitionedEithers 'のために行って、それを作ったし不変。 – slim

0

私はハスケルに精通していないので、質問に完全な答えを出すことはできません。

しかし、私はJavaジェネリックについて少し知っています。 Map<Boolean, Either<? extends Object, ? extends Object>>

を返す

streamOfEithers.collect(Collectors.groupingBy(Either::isLeft))

との問題は、型消去です。簡単に言えば、javaジェネリックは、他の多くの言語(例えば、C++のテンプレート)で同じタイプのロジックよりもはるかに弱いです。 Hereは、ジェネリックスができることとできないことの詳細な説明です。あなたが本当に深く掘ることを望むなら、私はhereを見ることを提案するでしょう。

1

はこれを試してみてください:

Map<Boolean, List<Either<Integer, String>>> collect = list.stream().collect(Collectors.partitioningBy(Either::isLeft)); 

は何Iである(あなたのいずれかの実装の一般的な型シグネチャがEither<L,R>であると仮定すると、サンプル実装でテストした場合)、型消去に問題はなく、期待どおりにコンパイルされます。その後

、あなたはこのようなあなたのPair初期化することができます:それは私がやったのと同じ結論になるとして、これを受け入れ

Pair<List<Integer>, List<String>> result = 
     pair(
      collect.getOrDefault(true, Collections.emptyList()).stream().map(Either::left).collect(toList()), 
      collect.getOrDefault(false, Collections.emptyList()).stream().map(Either::right).collect(toList())); 
関連する問題