java 当需要按键排序时,迭代HashMap〈Integer,X>的最佳方法

qv7cva1a  于 2023-04-19  发布在  Java
关注(0)|答案(2)|浏览(91)

我有一个代码如下:

private final HashMap<Integer, X> map = new HashMap<>();

我需要将HashMap条目转换为一些DTO的列表(基于Map中的键和值)。我还需要它按键排序。
我注意到,由于我的密钥是整数,我可以通过以下方式访问它:

map.forEach(..);

而秩序却被拒绝了。这是最有效的方法吗?或者有更好的方法吗?
在这种情况下,我更关心效率而不是干净的代码。
编辑:我不想使用TreeMap,因为我也需要O(1)和NOT O(Log(N)来进行插入。

zpf6vheq

zpf6vheq1#

IYou说:
我注意到,由于我的密钥是整数,我可以通过以下方式访问它:
map.forEach(..);
命令被撤销
你看到一些数字以排序的顺序出现仅仅是运气,而不是真正的排序。Map接口和HashMap类在他们的Javadoc中明确声明他们不以任何特定的顺序迭代。
这意味着你不应该依赖任何明显的排序。即使当前的实现确实在内部使用了排序,该实现也可以在未来的版本中自由更改为不同的排序或任意顺序,从而破坏你的应用。
👉**如果您想排序,您必须支付排序。**您可以选择提前支付或稍后支付。

提前支付

使用NavigableMap(或SortedMap)提前付款,它按键的顺序维护您的条目。
TreeMap类是这些接口的一个实现。如果你需要并发性,ConcurrentSkipListMap是另一个。

private final NavigableMap<Integer, X> map = new TreeMap<>();

稍后支付

先填充Map(如HashMap),然后再付款。完成Map后,进行排序。

  • 您可以使用Stream进行排序,如智能Answer by WJS中所示。
  • 或者,您可以通过从Map构建NavigableMap进行排序。
private final Map<Integer, X> map = new HashMap<>();
…
private final NavigableMap<Integer, X> navMap = new TreeMap<>( map ) ;

举个例子。

Map < Integer, String > map =
        Map.of(
                3 , "Carol" ,
                1 , "Alice" ,
                2 , "Bob"
        );
NavigableMap < Integer, String > navMap = new TreeMap <>( map );

System.out.println( "map = " + map );
System.out.println( "navMap = " + navMap );

运行时,请注意map如何以不同于创建顺序的顺序打印。相反,navMap始终以键排序的顺序打印。

map = {2=Bob, 1=Alice, 3=Carol}
navMap = {1=Alice, 2=Bob, 3=Carol}

或者,在您的例子中,您正在以特定顺序生成您想要的List。您可以稍后通过以非排序顺序生成列表,然后对该列表进行排序来支付。您可以按自然顺序排序或通过指定Comparator进行排序。

Collections.sort( list ) ;

你说:
我不想使用TreeMap,因为我也需要O(1)和NOT O(Log(N)来进行插入。
注意过早的优化。除非你有大量的元素,或者经常重复这段代码,否则我会惊讶地发现任何重大的影响。执行一些基准测试或分析,而不是假设性能瓶颈。

yqyhoc1h

yqyhoc1h2#

我需要将HashMap条目转换为一些DTO的列表(基于Map中的键和值)。我还需要它按键排序。
在插入过程中是否使用TreeMap或更高版本进行排序取决于您,但您仍然需要进行排序并产生成本。但为了解决您的问题,这里有一个替代方案。

  • 声明DTO(这里我使用的是一个记录)
  • 流式传输Map条目设置
  • 按键排序创建每个DTO,以列表的形式返回它们。
record DTO<X>(Integer getInt, X getX) {}
Map<Integer, String> map = new HashMap<>(); // populated with the data
List<DTO<String>> list = map.entrySet().stream()
        .sorted(Entry.comparingByKey())
        .map(e -> new DTO<String>(e.getKey(), e.getValue()))
        .toList();

上面返回的列表将是不可变的。您也可以更改.toList()以返回特定类型的集合。下面是一个返回ArrayList的集合。

.collect(Collectors.toCollection(ArrayList::new));

相关问题