我需要根据另一个流过滤一个流,并获取所有匹配条目的计数。
我尝试了以下方法和其他各种组合,但无法正常工作。
想法是:
这基本上是根据流2中的出现找到流1中数字的频率。
流2是
int[] chars = {332, 255, 271, 232, 194, 39, 162, 89, 200, 126, 225, 218, 42, 237, 87, 63, 63, 229};
以下代码的预期输出是:
[0,0,0,...,1/18for39,0,0,1/18for42,0,0,...,2/18for63,...,1/18for87,0,1/18for89,...1/18for126,0,0,...1/18for162,0,0,...,etc..1/18for255,0]
任何帮助将不胜感激。预先感谢。
BiPredicate<Integer, Integer> predicate = (d, f) -> Integer.valueOf(d)
.equals(Integer.valueOf(f));
List<Double> fractions = chars.filter(value -> IntStream.rangeClosed(0, 256)
.anyMatch(nbr -> predicate.test(value, nbr)))
.count()
.map(x -> x)
.mapToDouble(x -> x / chars.size())
.boxed()
.collect(Collectors.toList());
答案 0 :(得分:0)
我会做些不同的事情,以解决手头的问题:
IntStream idents = ...; // Your 0-256
IntStream input = ...; // your random numbers
//Generate a map of input numbers to how often they occur
Map<Integer, Long> freq = input.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
//No need for the stream's source, use the map
long total = freq.values().stream().reduce(0L, Long::sum); // your 18
有了我们的频率图,就可以轻松创建我们想要的东西。我回答了我的建议,也满足了您的要求:
//Generating the 0-256 array in double form
double[] result = idents.mapToDouble(i -> freq.getOrDefault(i, 0) / (double) total).toArray();
说实话,仅使用频率图来确定所需信息,我认为这样做没有多大意义。
//Find the fraction for 39:
double value = freq.getOrDefault(39, 0) / (double) total;
//Find only the values in range:
Predicate<Integer> inRange = i -> i >= 0 && i <= 256;
freq.entrySet().stream().filter(e -> inRange.test(e.getKey())); //you now have a stream of the valid frequencies
//Or the values out of range
....filter(e -> inRange.negate().test(e.getKey()))
如果输入为空,则也可以立即返回数组。让我知道是否还有另一个我没有讲到的案例
答案 1 :(得分:0)
其他解决方案的替代方法(在迭代给定流的元素方面非常有效),但与您现有的尝试更接近的方法是将输入用作数组,以便在使用时可以使用size维处理它们,而不是执行anyMatch
,而只是filter
,对元素进行计数并计数,以进一步对平均值进行如下处理:
int[] chars = new int[]{332, 255, 271, 232, 194, 39, 162, 89, 200, 126, 225, 218, 42, 237, 87, 63, 63, 229};
List<Double> fractions = IntStream.rangeClosed(0, 256)
.mapToLong(value -> Arrays.stream(chars).filter(f -> value == f).count())
.mapToDouble(x -> (double) x / chars.length).boxed()
.collect(Collectors.toList());
答案 2 :(得分:0)
您应避免将源重复256次。如果是Stream,则无论如何都不能对其进行多次处理,但是即使您有允许对其进行多次迭代的源,也应避免在避免这种情况下经常这样做。
如果您想使其看起来像是单个Stream操作,则可以执行例如
int[] chars = {332, 255, 271, 232, 194, 39, 162, 89, 200, 126, 225, 218, 42, 237, 87, 63, 63, 229};
List<Double> fractions = Arrays.stream(chars).boxed()
.collect(Collectors.collectingAndThen(
Collectors.groupingBy(Function.identity(), Collectors.counting()),
map -> {
double total = map.values().stream().mapToInt(Long::intValue).sum();
return IntStream.rangeClosed(0, 256)
.mapToObj(i -> map.getOrDefault(i, 0L)/total)
.collect(Collectors.toList());
}));
但是使用Stream或“一个操作”本身并不是目的。
如果您想要一个简单而有效的解决方案,请考虑
int[] counts = new int[257];
for(int c: chars) if(c >= 0 && c <= 256) counts[c]++;
double total = chars.length;
List<Double> fractions
= Arrays.stream(counts).mapToObj(c -> c/total).collect(Collectors.toList());