如何用java流重新组合树映射

如何用java流重新组合树映射,java,java-8,java-stream,treemap,Java,Java 8,Java Stream,Treemap,我有一个TreeMap实例,我想重新分配键值映射,将最低的键分配给最低的值,将最高的键分配给最高的键 以下是我在没有流的情况下的做法: TreeMap<Integer, Integer> map = new TreeMap<>(); map.put(1, 6); map.put(2, 9); map.put(4, 2); map.put(3, 1); map.put(8, 10); map.put(5, 10); ArrayList<Integer

我有一个
TreeMap
实例,我想重新分配键值映射,将最低的键分配给最低的值,将最高的键分配给最高的键

以下是我在没有流的情况下的做法:

 TreeMap<Integer, Integer> map = new TreeMap<>();
 map.put(1, 6);
 map.put(2, 9);
 map.put(4, 2);
 map.put(3, 1);
 map.put(8, 10);
 map.put(5, 10);

 ArrayList<Integer> valueList = new ArrayList<Integer>(map.values());
 Collections.sort(valueList);

 int i = 0;
 for (Map.Entry entry : map.entrySet()) {
      entry.setValue(valueList.get(i++));
 }

 System.out.println(map);
欢迎提供如何利用java-8流API执行此类任务的任何提示


Thx

我找到了一种非常容易阅读和使用的解决方案:

Iterator<Integer> keyIterator = map.keySet().iterator();
TreeMap<Integer, Integer> newMap = map.values().stream()
    .sorted()
    .map(value -> new SimpleEntry<>(keyIterator.next(), value))
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (l, r) -> l, TreeMap::new)); 
。。。但它有一个明显的缺点:

我不能保证这将并行工作,因为它取决于
keyinterator.next()
的结果,该结果也未被选中。请在该部分阅读更多内容。我不想用这种方式


如果我是你,我会利用迭代器的优点:

Iterator<Integer> values = valueList.iterator();
Iterator<Integer> keys = map.keySet().iterator();

TreeMap<Integer, Integer> newMap = new TreeMap<>();   // create a new Map
while (values.hasNext() && keys.hasNext()) {          // iterate simultaneously
    newMap.put(keys.next(), values.next());           // put the key-value
}
Iterator values=valueList.Iterator();
迭代器键=map.keySet().Iterator();
TreeMap newMap=newtreemap();//创建新地图
while(values.hasNext()&&keys.hasNext()){//同时迭代
newMap.put(key.next(),values.next());//放置键值
}

你的方法不错。你可以把它缩短到

PriorityQueue<Integer> q = new PriorityQueue<>(map.values());
map.entrySet().forEach(e -> e.setValue(q.remove()));
PriorityQueue q=newpriorityqueue(map.values());
map.entrySet().forEach(e->e.setValue(q.remove());

我不认为这个任务适合流API。

提示:您的
收集
操作的
供应商
应该与构建
树映射
相关(该树映射自然按这些键的性质排序,没有
比较器
)。一旦你尝试了,但没有成功,请标记我以撤回接近票数的投票。
LinkedList valueList=new LinkedList(map.values());集合。排序(valueList);map.entrySet().forEach(entry->entry.setValue(valueList.pop())@HadiJ:将其作为答案发布:)@Nikolas,谢谢你的投票。与我的解决方案相比,OP解决方案的成本较低。我相信解决方案的清晰度和可维护性高于性能。简化一点
map.values().stream().sorted().collect(collector.toMap(k->keyierator.next(),Function.identity(),(l,r)->l,TreeMap::new))@HadiJ:是的,映射可以发生在收集器内部。如果你不介意的话,我已经编辑了我的答案,其中提到了你。@HadiJ和Nikolas非常可读且清晰的解决方案+1。我试着在一个流中做这件事,而不引用地图旁边的任何其他变量,但到目前为止,我还没有想到怎么做。@pero_hero,我想这是不可能的。这是另一种方法:
Map-reMap=Map.entrySet().stream().sorted(Map.Entry.comparingByValue()).collect(Collectors.toMap(k->Map.pollFirstEntry().getKey(),Map.Entry::getValue,(a,b)->a,LinkedHashMap::new))@HadiJ我现在设法让它在没有其他引用的情况下运行,但它又丑又慢一个好答案,我认为这些实现被低估了。顺便说一句,您可以编程到一个接口:
Queue q=newpriorityqueue(map.values())。非常简洁,性能良好+1。您的假设是正确的,这个问题不容易“流化”,但想学习一些东西。@Nikolas我的第一个变体是
var q=new PriorityQueue(map.values())
,然后我将其更改为与
java-8
标记匹配。定义API时,我总是使用最抽象的类型,如您所建议的。对于仅在后续行中使用的局部变量,它没有那么重要。
Iterator<Integer> values = valueList.iterator();
Iterator<Integer> keys = map.keySet().iterator();

TreeMap<Integer, Integer> newMap = new TreeMap<>();   // create a new Map
while (values.hasNext() && keys.hasNext()) {          // iterate simultaneously
    newMap.put(keys.next(), values.next());           // put the key-value
}
PriorityQueue<Integer> q = new PriorityQueue<>(map.values());
map.entrySet().forEach(e -> e.setValue(q.remove()));