【问题标题】:Get values from HashMap as reference从 HashMap 中获取值作为参考
【发布时间】:2016-06-21 11:07:21
【问题描述】:

是否可以从HashMap 获取值列表作为参考

class MyCustomObject {
    String name;
    Integer id;

    MyCustomObject(String name, Integer id){
        this.name = name;
        this.id = id;
    }
}
HashMap<Integer, MyCustomObject> map = new LinkedHashMap<>();
map.put (1, new MyCustomObject("abc",1));
map.put (2, new MyCustomObject("xyz",2));

List<MyCustomObject> list = new ArrayList<>(map.values());

Log.i(TAG,"************ List from HashMap ************");
for (MyCustomObject s : list) {
     Log.i(TAG,"name = "+s.name);
}

list.set(0,new MyCustomObject("temp",3));

Log.i(TAG,"************ List from HashMap after update ************");
for (MyCustomObject s : list) {
      Log.i(TAG,"name = "+s.name);
}

Log.i(TAG,"************ List from HashMap ************");

List<MyCustomObject> list2 = new ArrayList<>(map.values());
for (MyCustomObject s : list2) {
     Log.i(TAG,"name = "+s.name);
}

输出

**************** List from HashMap ***************
name = abc
name = xyz
**************** List from HashMap after update ***************
name = temp
name = xyz
**************** List from HashMap ***************
name = abc
name = xyz

如果从HashMap 获取值列表,则返回深拷贝。

更新

我的要求

  1. 我想要 HashMap 中的值列表,因为我想使用它们的位置访问项目
  2. 我想保留值的顺序
  3. 如果我修改提取列表中的任何内容,那么它也应该反映在 HashMap 中

请告知是否有任何第三方库提供此类数据结构,或者处理这种情况的最佳方法是什么

【问题讨论】:

  • List&lt;MyCustomObject&gt; list = new ArrayList&lt;&gt;(map.values()); 你觉得这条线有什么作用?
  • 是浅拷贝,你到底想要什么?
  • 问题是哈希图不知道索引,因此您无法获得由地图支持的列表。即使有可能list.set(0, whatever) 对地图没有多大意义,因为无论如何您都需要访问/检查密钥,在这种情况下,您只需调用map.put(key, whatever)
  • 我想要的是,如果我从列表中更新 MyCustomObject,它也应该反映在 HashMap 中

标签: java hashmap linkedhashmap shallow-copy


【解决方案1】:

您正在根据Map 的值创建一个新的List

List<MyCustomObject> list = new ArrayList<>(map.values());

这就是创建值 Collection 的副本的原因,而 List 中的更改无法反映在原始 Map 中。

如果直接修改map.values()返回的Collection(例如map.values().remove(new MyCustomObject("abc",1))),会体现在原来Map的内容中。但是,您将无法在Collection 上调用set,因为Collection 没有该方法。

【讨论】:

    【解决方案2】:

    集合值()

    返回此映射中包含的值的集合视图。这 集合由地图支持,因此地图的更改会被反映 在集合中,反之亦然。

    所以使用一个集合并将values() 分配给它。或entrySet()

    【讨论】:

    • 正是我的建议,即使用 entrySet()entry.setValue(...) 来更新该条目。
    • @Thomas +1 来自我,entrySet 比值更常用,因为键经常发挥作用。
    【解决方案3】:

    尝试使用地图支持的地图条目,并通过调用entrySet() 获得。一个列表几乎可以像你想要的那样工作(尽管我仍然建议你直接使用map.put( key, updatedValue )

    例子:

    Map<String, Integer> map = new HashMap<>();
    map.put( "a", 1 );
    map.put( "b", 2 );
    
    //you create a list that's not backed by the map here but that isn't a problem
    //since the list elements, i.e. the entries, are backed by the map
    List<Entry<String, Integer>> entryList = new ArrayList<>(map.entrySet());
    entryList.get(0).setValue( 5 );
    
    System.out.println( map ); //prints: {a=5, b=2} (note that order is a coincidence here)
    

    最后一点:正如我在评论中所说,处理地图顺序并不总是确定性的(除非你知道你正在处理像TreeMap 这样的有序地图),因此使用索引可能会引入错误或不良行为。这就是为什么在大多数情况下您至少要检查密钥的原因,因此您要么需要使用Map.Entry(顺便说一句,出于充分的理由,它的密钥不能更改)或直接使用密钥,在这种情况下你不需要'无论如何都不需要值或条目的列表/集合。

    【讨论】:

    • 这是最接近我需要的
    • 如果我使用 LinkedHashMap 而不是 HashMap,订单将是确定性的吗? map.entrySet() 将始终以相同的顺序提供数据
    • @penguin a LinkedHashMap 具有确定性顺序,但用于处理列表索引的算法可能仍然不知道它。除此之外,LinkedHashMap 更像是一种妥协/混合,就地图部分而言,索引没有任何意义。也就是说,我发现依赖不打算以这种方式使用的集合的妥协或属性是危险的。
    猜你喜欢
    • 2017-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-26
    • 2018-12-06
    相关资源
    最近更新 更多