Java使用Steams VS TreeMap对地图进行排序

时间:2019-01-19 04:00:24

标签: java dictionary hashmap

考虑以下Java HashMap。

Map<String, String> unsortMap = new HashMap<String, String>();
unsortMap.put("Z", "z");
unsortMap.put("B", "b");
unsortMap.put("A", "a");
unsortMap.put("C", "c");

现在,我希望按“关键字”对该地图进行排序。一种选择是让我为此目的使用TreeMap。

Map<String, String> treeMap = new TreeMap<String, String>(unsortMap);

另一个选择是让我将Java流与Sorted()一起使用,如下所示。

Map<String, Integer> sortedMap = new HashMap<>();
unsortMap.entrySet()
    .stream()
    .sorted(Map.Entry.comparingByKey())
    .forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));

在这两个选项中,哪个选项更可取,为什么(在性能方面)?

谢谢

3 个答案:

答案 0 :(得分:2)

正如其他人指出的那样,将已排序的条目流转储到常规HashMap中将无济于事……LinkedHashMap是合乎逻辑的选择。

但是,上述方法的替代方法是充分利用Stream Collectors API。

Collectors具有toMap方法,可让您为Map提供替代实现。因此,您可以像这样要求HashMap来代替LinkedHashMap

unsortedMap.entrySet()
    .stream()
    .sorted(Map.Entry.comparingByKey())
    .collect(Collectors.toMap(
       Map.Entry::getKey,
       Map.Entry::getValue,
       (v1, v2) -> v1, // you will never merge though ask keys are unique.
       LinkedHashMap::new
    ));

在使用TreeMap和LinkedHashMap之间...构造的复杂性可能类似于O(n log n)...显然,TreeMap解决方案是一个更好的方法,如果您打算保留在其中添加更多元素...在这种情况下,我想您应该以{{1​​}}开始。 TreeMap选项的优势在于,在链接或原始未排序的地图上查找将为O(1),而TreeMap的查找类似于LinkedHashMap,因此如果您需要保留未排序的地图进行高效查找,而如果您构建LinkedHashMap,则可以扔掉原始的未排序地图(从而节省一些内存)。

要使O(log n)的工作效率更高,您应该在构造时提供所需大小的良好估算器,这样就不需要动态调整大小,因此您可以说{{{ 1}}。

我认为LinkedHashMap的使用更加简洁...因为可以使代码更小,因此除非存在实际的性能问题,否则可以使用我将使用的未排序和排序的链接映射方法来解决LinkedHashMap::new

答案 1 :(得分:1)

您的流代码甚至不会对地图进行排序,因为它是针对HashMap执行操作的,而LinkedHashMap本质上是未排序的。为了使第二个流示例正常工作,您可以使用Map<String, Integer> sortedMap = new LinkedHashMap<>(); unsortMap.entrySet() .stream() .sorted(Map.Entry.comparingByKey()) .forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue())); ,它可以保持插入顺序:

TreeMap

但是现在您的两个示例甚至都不是相同的基础数据结构。 TreeMap由树支持(如果我没记错的话,它是红色的黑色)。如果您希望能够以排序的方式进行迭代或快速搜索密钥,则可以使用LinkedHashMapvar foodNotPlaced; snake.forEach(function(segment) { if (food.x != segment.x and food.y != segment.y) { ctx.fillStyle = 'red'; ctx.fillRect(food.x, food.y, unit, unit); foodNotPlaced = false; } else { food.x = Math.floor(Math.random()*((cvsW/unit)-1)+1)*unit; food.y = Math.floor(Math.random()*((cvsW/unit)-1)+1)*unit; foodNotPlaced = True; }); 是哈希表,其中贯穿有一个链表。如果您需要保持插入顺序(例如在实施队列时),则可以使用它。

答案 2 :(得分:1)

第二种方法不起作用,当您调用LinkedHashMap时,它不保留看跌订单。您可能需要HashMap

TreeMap诉流(LinkedHashMap):

  1. 代码样式。使用TreeMap更加简洁,因为您可以一站式实现。
  2. 空间复杂度。如果原始地图为Map,则使用这两种方法都需要创建一个新的LinkedHashMap。如果原始地图为Map,则只需使用第一种方法创建一个新的LinkedHashMap。您可以通过第二种方法重复使用gem install
  3. 时间复杂度。它们都应具有O(nln(n))。