【问题标题】:Seek for an efficient way to generate my HashMap instance寻找一种有效的方法来生成我的 HashMap 实例
【发布时间】:2013-11-08 20:59:27
【问题描述】:

我有一个Person 类:

public class Person{
    private String name;
    //pleaese think this 'id' simply as an attribute of Person, same as e.g. age, height
    private long  id; 
    public Person(String name, long id){
         this.name = name;
         this.id = id;
     }
    public String getName(){
        return name;
    }
    public long getId(){
        return id;
    }
}

然后,我有一个 HashMap 实例,其中包含从服务器获取的多个 Persons:

//key is String type, it is a unique name-like string assigned to each Person 
//value is a Person object.
HashMap<String, Person> personsMap = GET_PERSONS_FROM_SERVER();

然后,我有一个人员 ID 数组:

long[] ids = new long[]{1,2,3,4,5, …}

我需要生成另一个 HashMap,它只包含id列在ids数组中的人:

// Only the person whose id is listed in ids array will be in the following Map
Map<String, Person> personNeeded = … ; 

如何以高效的方式获取personNeeded

【问题讨论】:

  • 您使用什么作为地图键?你能把 ID 设为地图键吗?
  • NO,ID 是 ID,键是分配给 Person 的另一个唯一名称
  • 返回一个id不是key的map很奇怪
  • Oskar,id 只是一个属性,不要认为它是 DB 中的 id,它可以是任何东西,例如年龄、身高……它实际上只是 Person 的一个属性。这样想也不奇怪。
  • 取决于... GET_PERSONS_FROM_SERVER() 中是否有任何范围仅返回与您的数组匹配的 ID?否则,打开一个循环,我的朋友!

标签: java arrays hashmap


【解决方案1】:

你可以试试这样的:

1 - 将您的数组转换为 Set 以便快速查找

2 - 分配足够大的Map 以避免重新散列(对于默认加载因子 0.75,分配实际地图大小的 4/3 以应对所有元素的 id 都在集合中的最坏情况)

public void subMap(Map<String, Person> personMap, Long[] idArray) {
    Set<Long> idSet = new HashSet<Long>(Arrays.asList(idArray));
    Map<String, Person> personSubMap = 
            new HashMap<String, Person>((personMap.size() *  4 / 3) + 1);
    for(Entry<String, Person> e : personMap.entrySet()) {
        if(idSet.contains(e.getValue().getId())) {
            personSubMap.put(e.getKey(), e.getValue());
        }
    }
}

【讨论】:

    【解决方案2】:

    如果地图键与 ID 没有任何关系,没有比对地图条目进行线性迭代更好的方法来找到拥有这些键的人。

    首先构造一个ID的集合数据结构,这样你就可以在恒定时间内检查一个人的ID是否在列表中:

    Set<Long> idSet = new HashSet<>();
    for (long id: ids) idSet.add(id);
    

    然后只需遍历条目:

    HashMap<String, Person> personsById = new HashMap<>();
    for (Map.Entry<String,Person> e : personsMap.entrySet()) {
        String key = e.getKey();
        Person val = e.getValue();
        if (idSet.contains(val.getId()) personsById.put(key, val);
    }
    

    【讨论】:

      【解决方案3】:

      这样做

      Long[] ids = new Long[]{1l,2l,3l,4l,5l};        
      ArrayList<Long> idList = new ArrayList<Long>(Arrays.asList(ids));       
      HashMap<String, Person> personsMap = new HashMap<String, Person>();
      HashMap<String, Person> newMap = new HashMap<String, Person>();
      
      for (Map.Entry<String, Person> entry :personsMap.entrySet()) {
            if(idList.contains(entry.getValue().getId())){
                   newMap.put(entry.getKey(), entry.getValue());
            }
      }
      

      【讨论】:

        【解决方案4】:

        您要么必须通过personsMap.values() 进行线性搜索,要么创建第二个Map,以您正在搜索的属性为关键字。

        搜索Map 或线性搜索是否更快取决于您的用例。 Maps 的构建速度可能很慢,但它们可以重复使用并提供非常快速的查找。如果您需要进行多次(实际上是多次)搜索,请搜索Map 路线。如果您只搜索一次 personMap 并且只需要得到一个非常小的子集,那么请进行线性搜索。

        【讨论】:

          【解决方案5】:

          您必须遍历所有 Person 对象并查找 id 匹配项。当你找到它们时,你必须将它们添加到你的第二个 HashMap 中。

          只要 id 只是 Person 对象的一个​​属性,您就必须遍历所有值,直到找到您要查找的值。

          【讨论】:

          • 谢谢,你的话也是我的计划,如果没有比这个更有效的方法,我会这样做。
          猜你喜欢
          • 1970-01-01
          • 2023-01-19
          • 2023-04-07
          • 2021-07-06
          • 2023-03-14
          • 1970-01-01
          • 1970-01-01
          • 2017-10-02
          • 1970-01-01
          相关资源
          最近更新 更多