長さ制限しない重複順列

先日公開した要素の重複(繰り返しを許す)順列、RepeatablePermutation
yipuran-core/RepeatablePermutation.java at master · yipuran/yipuran-core · GitHub
これは、元のリストより大きい長さの順列を抽出しようとすると、
size over の IllegalArgumentException を発生させるようにしている。

RepeatablePermutation.of(Arrays.asList("A", "B", "C")).compute(4);

は、IllegalArgumentException としている。
元のリストより大きい長さを求められるようにこれ以上、ロジックを修正するのが面倒であり、
以下の手段で作成できる。
https://github.com/yipuran/yipuran-core/tree/master/src/main/java/org/yipuran/util/pch
の下に公開した Homogeneous (重複あり組み合わせ)を求めてから
RepeatablePermutation を求める方法である。
サンプル

Homogeneous.of(Arrays.asList("A", "B", "C")).compute(4).stream()
.map(e->RepeatablePermutation.of(e).compute(4))
.collect(ArrayList<List<String>>::new, (r, t)->r.addAll(t), (r, t)->{})
.stream().distinct()
.map(e->e.stream().collect(Collectors.joining(""))).forEach(System.out::println);


distinct() を実行させて、余計に抽出したものを取り除いている。
このようにサンプルは。文字列だからそのまま distinct() が有効であるが、
任意のクラスオブジェクトであれば、
正しく、equals メソッドと hashCode メソッドがoverride できていれば、
この distinct が使える。

また、このままでは並びが元のリスト並びからあまりにもかけ離れてしまうので、
以下のように、ソートすれば、すっきりするだろう。

Homogeneous.of(Arrays.asList("A", "B", "C")).compute(4).stream()
.map(e->RepeatablePermutation.of(e).compute(4))
.collect(ArrayList<List<String>>::new, (r, t)->r.addAll(t), (r, t)->{})
.stream().distinct()
.sorted((a, b)->{
      int r = 0;
     for(int i=0;i < a.size(); i++){
          if ((r = a.get(i).compareTo(b.get(i))) != 0) break;
     }
     return r;
})
.map(e->e.stream().collect(Collectors.joining(""))).forEach(System.out::println);

もっと短く書く

Homogeneous.of(Arrays.asList("A", "B", "C")).compute(4).stream()
.map(e->RepeatablePermutation.of(e).compute(4))
.collect(ArrayList<List<String>>::new, (r, t)->r.addAll(t), (r, t)->{})
.stream().distinct()
.sorted((a, b)->{
    int r=0,i=0;
    while((r = a.get(i).compareTo(b.get(i)))==0) i++;
    return r;
})
.map(e->e.stream().collect(Collectors.joining(""))).forEach(System.out::println);