我有一个Integer的优先队列。PriorityQueue<Integer> pq
我想用声明的方式将其转换为一个映射。
poll
应该给钥匙size
应给下面是我试过的
pq.stream().collect(Collectors.groupingBy(queue::poll, queue::size));
但这是行不通的,因为方法引用不是功能接口Collectors。
所以我在寻找一种方法来实现这个功能。
我知道我可以直接使用一个循环,然后把条目放到地图中,但我希望在这里使用声明式的方式。
我有一个数字数组。然后,我想将数组中的每个值映射到一个整数,这个整数是小于数组中当前值的值的数量。
这是你应该在问题中说明的 :)
因为你想从函数上解决这个问题,我建议分两步解决。
下面的代码段可以实现这一点。
int[] array = { 42, 3, 100, 56, 3, 11 };
NavigableMap<Integer, Long> frequencyMap = Arrays.stream(array).boxed()
.collect(Collectors.groupingBy(Function.identity(), TreeMap::new,
Collectors.counting()));
Map<Integer, Long> countMap = frequencyMap.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey,
entry -> frequencyMap.headMap(entry.getKey())
.values().stream().mapToLong(Long::longValue).sum()));
System.out.println(countMap);
输出
{3=0, 100=5, 56=4, 42=3, 11=2}
如果你有一个 PriorityQueue<Integer>
而非 int[]
,你可以改变。
Arrays.stream(array).boxed()
改为:
queue.stream()
不管上面的代码段如何,我都建议用必要的方式来解决这个问题,而不是用功能来解决;这样会更容易读懂,你也能进一步优化它。
你在评论中陈述的需求让需求更容易理解。 我有一个数字数组。然后,我想将数组中的每个值映射到一个整数上,这个整数是小于数组中当前值的值的数目。.
我真的不相信这个操作很容易适合流处理,但你可以分两步来做。
List
int[] arr = {1,10,2,4,5,10,19,19,10};
List<Integer> list = Arrays.stream(arr).sorted().boxed().collect(Collectors.toList());
List
接口来获取比当前项少的相对项数。value
字段是用来存储重复键的列表。 重复键的索引被认为是等价的。LinkedHashMap
保留键的排序顺序Map<Integer, List<Integer>> map = list
.stream()
.collect(Collectors.groupingBy(a->a,
LinkedHashMap::new,
Collectors.mapping(b->list.indexOf(b),
Collectors.toList())));
map.entrySet().forEach(System.out::println);
印刷品
1=[0]
2=[1]
4=[2]
5=[3]
10=[4, 4, 4]
19=[7, 7]
这里的 PriorityQueue
被收集到一个映射,其中key是队列本身的int,value是比它小的数字量。
int[] array = { 42, 2, 100, 100, 17, 2, 33 };
List<Integer> ints = Arrays.stream(array).boxed().collect(toList());
PriorityQueue<Integer> priorityQueue = new PriorityQueue<Integer>(ints);
TreeMap<Integer, Long> collect1 = priorityQueue.stream()
.collect(toMap(
Function.identity(),
val -> priorityQueue.stream().filter(i -> val > i).count(),
(l, r) -> l,
TreeMap::new
)
);
输出。
{2=0, 17=2, 33=3, 42=4, 100=5}
直接回答我说的问题,一个PriorityQueue可以用流这样转换为Map。
Map<Integer, Integer> map = pq.stream().collect(ConcurrentHashMap::new, (integerIntegerHashMap, integer) -> integerIntegerHashMap.put(pq.poll(), pq.size()), ConcurrentHashMap::putAll);
这是一个并发的例子,但是用HashMap(或者其他任何非并发的Map)来代替,在那些不需要并发的场景中也可以用。
这个 collect
方法需要3个参数(docs.Stream.collect)。Stream.collect):
这里的容器是一个 ConcurrentHashMap
,而组合器是 putAll
方法(因为它需要一个集合)。
现在为我面临的实际问题提供答案:有一个整数数组,我需要创建一个新的整数数组,这个数组是原数与输入中小于它的值的数目的映射。
输入[1,2,3] -> 输出[0,1,2]输入[8,4,4] -> 输出[2,0,0]。
我是按照上面的用法来做的。
int[] nums = ... (this is the input)
PriorityBlockingQueue<Integer> pq = Arrays.stream(nums).parallel().boxed().collect(()->new PriorityBlockingQueue<>(nums.length, Comparator.reverseOrder()), PriorityBlockingQueue::add, PriorityBlockingQueue::addAll);
Map<Integer, Integer> map = pq.stream().collect(ConcurrentHashMap::new, (integerIntegerHashMap, integer) -> integerIntegerHashMap.put(pq.poll(), pq.size()), ConcurrentHashMap::putAll);
int[] out = Arrays.stream(nums).mapToObj(operand -> map.get(operand)).mapToInt(Integer::intValue).toArray();
我把容器设置为一个并发最大堆(一个带有反向比较器的并发优先级队列)。
然后把数字1个个拉出来,根据pq给它们相应的映射。我认为这第二步不能并行完成,因为2 poll
调用可能会连续完成,但我们需要保证的就是 size
后直接调用。poll
.
最后,对输入元素进行迭代,并从地图中获取相关的值,然后转换为结果数组。