C#から出てくる、私はいくつかのJava 8を学びたいと思っています。解決したい最初のおもちゃの問題は、Javaストリームを使用して数字n≥2の素因数を見つけます。Javaストリームをエレガントに使用して、数値の素因数を求める方法はありますか?
私の最初の試みは非常に厄介な感じ:私はここでの問題のカップルを持っている
// candidates stores numbers that possibly are prime factors
ArrayList<Integer> candidates = new ArrayList<Integer>();
IntStream.range(2, n + 1).forEach(i -> candidates.add(i));
// find the prime factors from the candidates list
ArrayList<Integer> primes = candidates.stream()
.reduce(new ArrayList<Integer>(),
// add current candidate <i> to prime list <a> if <i> divides <n>
// and <i> is not divided by any prime <p> stored in <a> so far
(a, i) -> {
if (n % i == 0 && a.stream().allMatch(p -> i % p != 0)) {
a.add(i);
}
return a;
},
// not required in sequential streams, I think
(a1, a2) -> { System.out.println("ouch"); return a1; }
);
:
私が使用している過負荷
reduce(U, BiFunction<U, T, U>, BinaryOperator<U>)
がIntStream
に定義されていませんが、Stream<Integer>
にのみしたがってIntStream.range(2, n + 1).reduce(…)
は機能しません。
reduce
は、副作用に依存しているため、非常に扱いにくいと感じています。理想的には、私は骨材としてStream<Integer>
を使用したいと思うし、その後、副作用なしで連結を使用し、すなわち/* … */.reduce(new ArrayList<Integer>().stream(), (a, i) -> (n % i == 0 && a.allMatch(p -> i % p != 0)) ? Stream.concat(a, Stream.of(i)) : a, (a1, a2) -> { System.out.println("ouch"); return a1; } )
しかし、これは
concat
を使用するときに「ストリームがすでに時またはクローズ操作された」スローします。だから私はStream.concat(Arrays.stream(a.toArray()), Stream.of(i))
で
a
を複製しようとしたが、Stream<Integer>
からStream<Object>
にはいくつかの変換が起こるので、これは、コンパイルされません。私はコンバイナは必要ありませんが、私はダミーを渡す必要があります。
どのようにこれらの問題を解決できますか?ところで
、C#バージョンである:
var primes = Enumerable.Range(2, n - 1)
.Aggregate(Enumerable.Empty<int>(),
(a, i) => (n % i == 0 && a.All(p => i % p != 0))
? a.Union(new int[] { i })
: a
)
;
この質問は、それは再帰的ストリームAPIを介して素因数を定義するのは非常に簡単ですWhat is the highest power of A that divides N factorial?
真にこの問題は、たとえC#の対応する概念に適しているとしても、必ずしもJavaストリームを使用するのに適切ではないようです。 –