Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 多键哈希映射_Java - Fatal编程技术网

Java 多键哈希映射

Java 多键哈希映射,java,Java,最近我参加了一次面试,将大量员工的详细信息保存在DS中 我以Hashmap的形式给出了解决方案,emp Id作为密钥 接下来的问题是,用户是否希望基于名称进行搜索,以及如何实现它。我建议使用emp名称作为键,并使用与Arraylist相同的名称保存所有员工 接下来的问题很棘手,需要创建一个地图,用户可以根据emp Id或emp名称进行搜索。如何在map中实现这一点 在内存中高效地实现它。这是一个肮脏的解决方案(是的——非常肮脏,永远不要在生产环境中这样做!),但如果键是不同类型的,并且一个不是另

最近我参加了一次面试,将大量员工的详细信息保存在DS中

我以Hashmap的形式给出了解决方案,emp Id作为密钥

接下来的问题是,用户是否希望基于名称进行搜索,以及如何实现它。我建议使用emp名称作为键,并使用与Arraylist相同的名称保存所有员工

接下来的问题很棘手,需要创建一个地图,用户可以根据emp Id或emp名称进行搜索。如何在map中实现这一点


在内存中高效地实现它。

这是一个肮脏的解决方案(是的——非常肮脏,永远不要在生产环境中这样做!),但如果键是不同类型的,并且一个不是另一个的子类型(例如
字符串
),它将起作用。按两个键放置每个员工,并按提供的键获取,可以是
id
name

Map<?, List<Employee>> map = new HashMap<>();

public void putEmployee(Employee e) {
    map.put(e.id, Arrays.asList(e));    // put by id
    if (!map.containsKey(e.name)) {
        map.put(e.name, new ArrayList<>());
    }
    map.get(e.name).add(e);             // put by name
}

public Employee getById(long id) {
    return map.containsKey(id) ? map.get(id).get(0) : null;
}

public List<Employee> getByName(String name) {
    return map.containsKey(name) ? map.get(name) : Collections.emptyList();
}

Map一种方法是创建一个
Key
对象,该对象可以通过名称或id进行搜索:

public enum KeyType {
    ID, NAME;
}

public class SearchKey {
    private KeyType keyType;
    private String value;

    // constructor and getters snipped for brevity's sake

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        SearchKey searchKey = (SearchKey) o;

        return keyType == searchKey.keyType && value.equals(searchKey.value);

    }

    @Override
    public int hashCode() {
        int result = keyType.hashCode();
        result = 31 * result + value.hashCode();
        return result;
    }

public class Directory {
    private Map<SearchKey, Set<Employee>> directory = new HashMap<>();

    public void addEmployee(Employee e) {
        // Add search by id
        directory.put
            (new SearchKey(KeyType.ID, e.getId()), Collections.singleton(e));

        // Add search by name
        SearchKey searchByName = new SearchKey(KeyType.NAME, e.getName());
        Set<Employee> employees = directory.get(searchByName);
        if (employees == null) {
            employees = new HashSet<>();
            directory.put(searchByName, employees);
        }
        employees.add(e);
    }

    public Employee getById (String id) {
        // Assume that the ID is unique
        return directory.get(new SearchKey(KeyType.ID, id)).iterator().next();
    }

    public Set<Employee> getByName (String name) {
        return directory.get(new SearchKey(KeyType.NAME, name));
    }
}
公共枚举密钥类型{
身份证、姓名;
}
公共类搜索密钥{
私钥类型;
私有字符串值;
//为了简洁起见,构造函数和getter被剪掉了
@凌驾
公共布尔等于(对象o){
if(this==o){
返回true;
}
如果(o==null | | getClass()!=o.getClass()){
返回false;
}
SearchKey SearchKey=(SearchKey)o;
返回keyType==searchKey.keyType&&value.equals(searchKey.value);
}
@凌驾
公共int hashCode(){
int result=keyType.hashCode();
result=31*result+value.hashCode();
返回结果;
}
公共类目录{
私有映射目录=new HashMap();
公共无效添加员工(员工e){
//添加按id搜索
目录.put
(新的SearchKey(KeyType.ID,e.getId()),Collections.singleton(e));
//按名称添加搜索
SearchKey searchByName=新的搜索键(KeyType.NAME,e.getName());
设置employees=directory.get(searchByName);
if(employees==null){
employees=newhashset();
directory.put(searchByName,employees);
}
增加(e);
}
公共雇员getById(字符串id){
//假设ID是唯一的
return directory.get(newsearchkey(KeyType.ID,ID)).iterator().next();
}
公共集getByName(字符串名称){
返回directory.get(新的SearchKey(KeyType.NAME,NAME));
}
}

这是一个非常容易回答的问题:只需将id转换为字符串,并将员工存储两次——一次在名称下,另一次在id下作为字符串

您使用列表作为值的想法很好-对于IDs,列表的大小为1

请注意,最好使用两个映射,因为每个ID只有一名员工,并且不必将大小为1的列表作为退化情况处理,因此:

Map<Integer, Employee> employeesById;
Map<String, Set<Employee>> employeesByName;
Map employeesById;
映射employeesByName;

特别要注意的是,只使用一个映射不会占用更少的内存。事实上,与在单独的映射中存储员工的ID键和姓名键相比,您会占用更多的内存。

我想出了一个解决方案。请发表您的建议

步骤1:以emp id为键,emp对象为值,形成hashmap

步骤2:为相同的名称创建一个与名称匹配的emp id列表,例如:name='XYZ'id={101102103,…}

步骤3:将此名称作为键和arraylist作为值插入同一映射


在这里,我们不会两次存储完整的员工详细信息。只是尝试维护姓名和id之间的关系。因此相对而言,它可以节省内存。

那么,您将如何开始这样做?一个技巧是使用[name+id]作为键。我想如果id是整数并且命名为字符串,冲突是不可能的。可能更适合程序员网站,因为这个问题不涉及在编程问题上寻求帮助。@Tunaki它将如何帮助?假设我需要检索所有
Peter
s,我应该请求什么键?@Tunaki那么如果我按名称搜索??如何过滤?我会为一家公司运行一种方法,它会对这样的东西感到满意。@async我相信问题是关于Java功能的,而不是关于编写干净的代码。我需要强调答案中的第一句和最后一句。我相信这个问题只是一个愚蠢的问题。如果他们想知道候选人是否了解Java功能,那么y应该明确地问这个问题,而不是发明这个场景。顺便说一句,这里不是判断你的解决方案,而是问题。@Sasha:谢谢你花时间给出解决方案。但我觉得这就像创建一个包含两次记录的地图一样。(一个作为id,一个作为名称).键入
映射的安全变体谢谢你的想法。但是存储员工详细信息两次会让我们消耗更多内存。有没有更好的解决方案?@Lathy没有,你不会消耗更多内存!映射中只存储引用,而不存储对象本身(内存中每个员工只有一个副本),因此,您所拥有的只是另一个映射中的一个映射条目(实际上只是一对引用)(不管它在哪个映射中,您都需要该条目)。另外,您不必创建不必要的列表来存储单个条目。使用两个映射会减少内存使用,而不是更多。嗯,我同意。您对我的解决方案有什么看法?@lathy您的解决方案需要一个
映射
-混合键类型和混合值类型。如果这样做了,为什么不这样做呢,但您必须牺牲java的强大功能如果面试问题是一个“谜题”不打算在生产中使用,那么你的吸力是一个很好的吸力-这并不比你只使用一个贴图的人工和糟糕的设计要求更糟糕。我有一个疑问,你说在你上面提到的解决方案中,你会将名称保存为键,但新对象(值)不会覆盖旧值?