地图的密钥可以与值的一部分共享吗?

时间:2015-07-15 03:46:01

标签: c++ c++11

可以将std::mapstd::unordered_map的密钥与值的一部分共享吗?特别是如果密钥非常重要,比如说std::string

作为一个简单的例子,我们来一个Person对象:

struct Person {
    // lots of other values
    std::string name;
}

std::unordered_map<std::string, std::shared_ptr<Person>> people;
void insertPerson(std::shared_ptr<Person>& p) {
    people[p.name] = p;
    //    ^^^^^^
    //    copy of name string
}

std::shared_ptr<Person> lookupPerson(const std::string& name) const {
    return people[name];
}

我的第一个想法是指向该人的名称的包装,但我无法弄清楚如何按名称进行查找。

2 个答案:

答案 0 :(得分:1)

出于您的目的,std::map可以被视为包含std::set的{​​{1}},根据该对的第一个元素对其进行排序(并因此可以高效访问)

如果键元素和值元素部分相同,则此视图特别有用,因为您不需要人为地分隔集合的值和键元素(并且您不需要围绕选择键的值编写包装器)。

相反,只需要提供一个自定义排序功能,该功能可以在集合上工作并提取相关的关键部分。

遵循这个想法,你的例子变成了

std::pair

作为替代方案,在这里您也可以删除自定义比较并按共享指针中的地址(支持auto set_order = [](auto const& p, auto const& s) { return p->name < s->name; }; std::set<std::shared_ptr<Person>, decltype(set_order)> people(set_order); void insertPerson(std::shared_ptr<Person>& p) { people.insert(p); } )对集合进行排序,因此可以直接在集合中使用:

<

在需要时将std::set<std::shared_ptr<Person> > people; void insertPerson(std::shared_ptr<Person>& p) { people.insert(p); } 替换为set(通常您还需要提供合适的哈希函数)。

编辑:可以使用unordered_set执行查找:

std:lower_bound

DEMO

编辑2 :但是,考虑到这个或多或少的丑陋的东西,你也可以按照你的主要思路,并使用一个小的包装器作为键的值,如

std::shared_ptr<Person> lookupPerson(std::string const& s)
{
    auto comp =  [](auto const& p, auto const& s) { return p->name < s; };
    return *std::lower_bound(std::begin(people), std::end(people), s, comp);
}

使用它(未经测试)

struct PersonKey
{
    PersonKey(std::shared_ptr<Person> const& p) : s(p->name) {}
    PersonKey(std::string const& _s) : s(_s) {}

    std::string s;
    bool operator<(PersonKey const& rhs) const
    {
         return s < rhs.s;
    }
};

通过

完成查找
std::map<PersonKey, std::shared_ptr<Person> > m;
auto sptr = std::make_shared<Person>("Peter");
m[PersonKey(sptr)]=sptr;

现在我比我的第一个建议更喜欢这个; - )

答案 1 :(得分:0)

这是davidhigh回答的替代方案。

struct Person {
    // lots of other values
    std::string name;
}

struct StrPtrCmp {
    bool operator()(const std::string* a, const std::string* b) const {
        return *a < *b;
    }
}

std::map<const std::string*, std::shared_ptr<Person>, StrPtrCmp> people();
void insertPerson(std::shared_ptr<Person>& p) {
    people[&(p.name)] = p;
}

std::shared_ptr<Person> lookupPerson(const std::string& name) const {
    return people[&name];
}

进行一些编辑以使其适用于std::unordered_map

struct StrPtrHash {
    size_t operator()(const std::string* p) const {
        return std::hash<std::string>()(*p);
    }
};

struct StrPtrEquality {
    bool operator()(const std::string* a, const std::string* b) const {
        return std::equal_to<std::string>()(*a, *b);
    }
};

std::unordered_map<const std::string*, std::shared_ptr<Person>, StrPtrHash, StrPtrEquality> people();