简体   繁体   English

实施地图的正确方法 <MyObject,ArrayList<MyObject> &gt;

[英]Correct way to implement Map<MyObject,ArrayList<MyObject>>

I was asked this in interview. 面试中有人问我这个问题。 using Google Guava or MultiMap is not an option. 不能使用Google GuavaMultiMap I have a class 我有一堂课

public class Alpha
{
     String company;
     int local;
     String title;
}

I have many instances of this class (in order of millions). 我有很多此类的实例(以百万计)。 I need to process them and at the end find the unique ones and their duplicates. 我需要处理它们,最后找到唯一的及其重复项。 eg 例如

instance --> instance1, instance5, instance7 (instance1 has instance5 and instance7 as duplicates)
instance2 --> instance2 (no duplicates for instance 2)

My code works fine 我的代码工作正常

declare datastructure 声明数据结构

HashMap<Alpha,ArrayList<Alpha>> hashmap = new HashMap<Alpha,ArrayList<Alpha>>();

Add instances 添加实例

for (Alpha x : arr)
{
    ArrayList<Alpha> list = hashmap.get(x); ///<<<<---- doubt about this. comment#1
    if (list == null)
    {
        list = new ArrayList<Alpha>();
        hashmap.put(x, list);
    }
        list.add(x);
}

Print instances and their duplicates. 打印实例及其副本。

for (Alpha x : hashmap.keySet())
{
    ArrayList<Alpha> list = hashmap.get(x); //<<< doubt about this. comment#2
    System.out.println(x + "<---->");
    for(Alpha y : list)
    {
        System.out.print(y);
    }
    System.out.println();
}

Question: My code works, but why? 问题:我的代码有效,但是为什么呢? when I do hashmap.get(x); 当我做hashmap.get(x); (comment#1 in code). (代码中的注释1)。 it is possible that two different instances might have same hashcode. 两个不同的实例可能具有相同的哈希码。 In that case, I will add 2 different objects to the same List. 在这种情况下,我将2个不同的对象添加到同一List。

When I retrieve, I should get a List which has 2 different instances. 当我检索时,我应该得到一个包含2个不同实例的列表。 (comment#2) and when I iterate over the list, I should see at least one instance which is not duplicate of the key but still exists in the list. (评论2),当我遍历列表时,我应该看到至少一个实例,该实例不是键的重复项,但仍存在于列表中。 I don't. 我不。 Why?. 为什么?。 I tried returning constant value from my hashCode function, it works fine. 我尝试从我的hashCode函数返回常量值,它工作正常。

If you want to see my implementation of equals and hashCode ,let me know. 如果要查看我的equalshashCode ,请告诉我。

Bonus question: Any way to optimize it? 奖励问题:有什么优化方法吗?

Edit: 编辑:

@Override
    public boolean equals(Object obj) {
        if (obj==null || obj.getClass()!=this.getClass())
            return false;
        if (obj==this)
            return true;
        Alpha guest = (Alpha)obj;
        return guest.getLocal()==this.getLocal()
                && guest.getCompany()  == this.getCompany()
                && guest.getTitle() == this.getTitle();
    }

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (title==null?0:title.hashCode());
    result = prime * result + local;
    result = prime * result + (company==null?0:company.hashCode());
    return result;
}

it is possible that two different instances might have same hashcode 两个不同的实例可能具有相同的哈希码

Yes, but hashCode method is used to identify the index to store the element. 是的,但是hashCode方法用于标识存储元素的索引。 Two or more keys could have the same hashCode but that's why they are also evaluated using equals . 两个或更多键可能具有相同的hashCode但这就是为什么还要使用equals对其进行评估的原因。

From Map#containsKey javadoc: Map#containsKey javadoc:

Returns true if this map contains a mapping for the specified key. 如果此映射包含指定键的映射,则返回true More formally, returns true if and only if this map contains a mapping for a key k such that ( key==null ? k==null : key.equals(k) ). 更正式地讲,当且仅当此映射包含键k的映射( key==null ? k==null : key.equals(k) )时,返回true (There can be at most one such mapping.) (最多可以有一个这样的映射。)


Some enhancements to your current code: 当前代码的一些增强功能:

  • Code oriented to interfaces . 面向接口的代码 Use Map and instantiate it by HashMap . 使用Map并通过HashMap实例化它。 Similar to List and ArrayList . 类似于ListArrayList
  • Compare String s and Object s in general using equals method. 通常使用equals方法比较StringObject == compares references, equals compares the data stored in the Object depending the implementation of this method. ==比较引用, equals根据此方法的实现比较存储在Object的数据。 So, change the code in Alpha#equals : 因此,更改Alpha#equals的代码:

     public boolean equals(Object obj) { if (obj==null || obj.getClass()!=this.getClass()) return false; if (obj==this) return true; Alpha guest = (Alpha)obj; return guest.getLocal().equals(this.getLocal()) && guest.getCompany().equals(this.getCompany()) && guest.getTitle().equals(this.getTitle()); } 
  • When navigating through all the elements of a map in pairs, use Map#entrySet instead, you can save the time used by Map#get (since it is supposed to be O(1) you won't save that much but it is better): 成对浏览地图的所有元素时,请改用Map#entrySet ,这样可以节省 Map#get所用的时间(因为假设为O(1),您不会节省那么多时间,但是效果更好) ):

     for (Map.Entry<Alpha, List<Alpha>> entry : hashmap.keySet()) { List<Alpha> list = entry.getValuee(); System.out.println(entry.getKey() + "<---->"); for(Alpha y : list) { System.out.print(y); } System.out.println(); } 

Use equals along with hashCode to solve the collision state. equalshashCode一起使用以解决冲突状态。

Steps: 脚步:

  • First compare on the basis of title in hashCode() 首先根据hashCode()的标题进行比较
  • If the title is same then look into equals() based on company name to resolve the collision state. 如果标题相同,则根据公司名称查找equals()以解决冲突状态。

Sample code 样例代码

class Alpha {
    String company;
    int local;
    String title;

    public Alpha(String company, int local, String title) {
        this.company = company;
        this.local = local;
        this.title = title;
    }

    @Override
    public int hashCode() {
        return title.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Alpha) {
            return this.company.equals(((Alpha) obj).company);
        }
        return false;
    }
}

...

Map<Alpha, ArrayList<Alpha>> hashmap = new HashMap<Alpha, ArrayList<Alpha>>();

hashmap.put(new Alpha("a", 1, "t1"), new ArrayList<Alpha>());
hashmap.put(new Alpha("b", 2, "t1"), new ArrayList<Alpha>());
hashmap.put(new Alpha("a", 3, "t1"), new ArrayList<Alpha>());

System.out.println("Size : "+hashmap.size());

Output 产量

Size : 2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM