我有Stream<Set<Integer>> intSetStream
。
我可以这样做......
Set<Integer> theSetWithTheMax = intSetStream.max( (x,y)->{ return Integer.compare( x.size(), y.size() ); } ).get( );
...我抓住了Set<Integer>
中Integer
元素数量最多的Set
。
太棒了。但我真正需要知道的是,Stream
中的第一个Set
是最大值吗?或者它是Stream
中的第10个i
?还是Set
i
?其中哪一个元素最多?
所以我的问题是:有没有办法 - 使用Stream API - 我可以确定&#34; 这是Set
Stream
在Set
Set.size( )
的{{1}}中,Stream<Set<Integer>>
来电&#34;?
我能想到的最佳解决方案是迭代intSetStream.iterator()
(使用max( )
)并进行手动Stream
计算。但是我希望能够学会更多的{{1}} - y方式去做;如果有这样的事情。
答案 0 :(得分:4)
您可以使用自定义收集器执行此操作:
int posOfMax = stream.mapToInt(Set::size)
.collect(() -> new int[] { 0, -1, -1 },
(a,i) -> { int pos = a[0]++; if(i>a[2]) { a[1] = pos; a[2] = i; } },
(a1,a2) -> {
if(a2[2] > a1[2]) { a1[1] = a1[0]+a2[1]; a1[2] = a2[2]; }
a1[0] += a2[0];
})[1];
这是最轻量级的解决方案。当我们使用专用类而不是数组时,它的逻辑变得更清晰:
int posOfMax = stream.mapToInt(Set::size)
.collect(() -> new Object() { int size = 0, pos = -1, max = -1; },
(o,i) -> { int pos = o.size++; if(i>o.max) { o.pos = pos; o.max = i; } },
(a,b) -> {
if(b.max > a.max) { a.pos = a.size+b.pos; a.max = b.max; }
a.size += b.size;
}).pos;
状态对象包含大小,它只是到目前为止遇到的元素数,最后遇到的最大值及其位置,如果当前元素大于最大值,我们将更新为大小的前一个值。这就是累加器函数(collect
的第二个参数)的作用。
为了支持任意评估命令,即并行流,我们必须提供组合器函数(collect
的最后一个参数)。它将两个部分评估的状态合并到第一个状态。如果第二个状态的最大值更大,我们更新第一个的最大值和位置,而我们必须将第一个状态的大小添加到第二个位置,以反映两个都是部分结果的事实。此外,我们必须将大小更新为两种大小的总和。
答案 1 :(得分:2)
执行此操作的一种方法是首先将Stream<Set<Integer>>
映射到Collection<Integer>
,其中每个元素的大小为每个Set<Integer>
,然后您可以提取给定的最大元素数Stream<Set<Integer>>
然后获取&#34;索引&#34;通过查找大小集合中最大数字的索引来设置此集合。
请考虑以下示例:
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class IntSetStreamExample {
public static void main(String[] args) {
final Stream<Set<Integer>> stream = Stream.of(
new HashSet<>(Arrays.asList(1,2,3)),
new HashSet<>(Arrays.asList(1,2)),
new HashSet<>(Arrays.asList(1,2,3,4,5)),
new HashSet<>(Arrays.asList(0)),
new HashSet<>(Arrays.asList(0,1,2,3,4,5)),
new HashSet<>()
);
final List<Integer> result = stream.map(Set::size).collect(Collectors.toList());
System.out.println("List of number of elements in Stream<Set<Integer>>: " + result);
final int max = Collections.max(result);
System.out.println("Largest set contains " + max + " elements");
final int index = result.indexOf(max);
System.out.println("Index of the largest set: " + index);
}
}
示例性输出可能如下所示:
List of number of elements in Stream<Set<Integer>>: [3, 2, 5, 1, 6, 0]
Largest set contains 6 elements
Index of the largest set: 4
答案 2 :(得分:1)
Streams方法的目的不是要知道迭代的当前元素 所以我认为你实际的方式:找到具有最大元素的Set,然后迭代集合以找到这个Set也不错。
作为替代方案,你可以先将Stream<Set<Integer>>
收集到一个List(以便有办法检索索引)并使用SimpleImmutableEntry
,但它似乎真的有点过分了:
Stream<Set<Integer>> intSetStream = ...;
List<Set<Integer>> list = intSetStream.collect(Collectors.toList());
SimpleImmutableEntry<Integer, Set<Integer>> entry =
IntStream.range(0, list.size())
.mapToObj(i -> new SimpleImmutableEntry<>(i, list.get(i)))
.max((x, y) -> {
return Integer.compare(x.getValue()
.size(),
y.getValue()
.size());
})
.get();
Integer index = entry.getKey();
Set<Integer> setWithMaxNbElements = entry.getValue();
答案 3 :(得分:1)
Collector
...使用该自定义public class IndexOfMaxCollector implements IntConsumer {
private int max = Integer.MIN_VALUE;
private int maxIdx = -1;
private int currIdx = 0;
public void accept( int value ){
if( value > max )
maxIdx = currIdx;
max = Math.max( max, value );
currIdx++;
}
public void combine( IndexOfMaxCollector other ){
if( other.max > max ){
maxIdx = other.maxIdx + currIdx;
max = other.max;
}
currIdx += other.currIdx;
}
public int getMax( ){ return this.max; }
public int getIndexOfMax( ){ return this.maxIdx; }
}
,我可以获取我的OQ的Collector
并确定包含最多元素的intSetStream
的索引,如下所示。
Set<Integer>
这个解决方案 - 诚然不是最好的&#34; 美丽&#34; - 在可重用性和可理解性赌注中,可能比其他人有一点优势。