在以下示例中尝试编写std::string
的{{1}}键时,键的编写顺序与初始化列表给出的顺序不同:
std::unordered_map
我希望看到'我为什么要排序',但我得到了一个类似Yoda的输出:
#include <iostream>
#include <unordered_map>
class Data
{
typedef std::unordered_map<std::string, double> MapType;
typedef MapType::const_iterator const_iterator;
MapType map_;
public:
Data(const std::initializer_list<std::string>& i)
{
int counter = 0;
for (const auto& name : i)
{
map_[name] = counter;
}
}
const_iterator begin() const
{
return map_.begin();
}
const_iterator end() const
{
return map_.end();
}
};
std::ostream& operator<<(std::ostream& os, const Data& d)
{
for (const auto& pair : d)
{
os << pair.first << " ";
}
return os;
}
using namespace std;
int main(int argc, const char *argv[])
{
Data d = {"Why", "am", "I", "sorted"};
// The unordered_map speaks like Yoda.
cout << d << endl;
return 0;
}
在sorted I am Why
here上阅读,我看到了这一点:
在内部,元素不按任何特定顺序排序,而是组织成存储桶。放置元素的哪个存储桶完全取决于其键的哈希值。这允许快速访问单个元素,因为一旦计算了散列,它就是指元素被放入的确切存储桶。
这就是为什么元素的排序方式与初始化列表中的排序方式不同?
当我希望按照与初始化列表相同的方式对键进行排序时,我会使用什么数据结构?我应该在内部保留一个字符串向量以某种方式保存参数顺序吗?通过选择特定的散列函数,可以以某种方式关闭存储桶组织吗?
答案 0 :(得分:4)
当我希望按照与初始化列表相同的方式对键进行排序时,我会使用什么数据结构?我应该在内部保留一个字符串向量以某种方式保存参数顺序吗?
也许您想要的只是(键,值)对的列表/向量?
如果你想要O(1)查找(hashmap)和迭代的顺序与插入顺序相同 - 那么是的,使用vector
和unordered_map
听起来是个好主意。例如,Django的SortedDict
(Python)就是这样做的,这里是灵感来源:
https://github.com/django/django/blob/master/django/utils/datastructures.py#L122
Python 2.7的OrderedDict
有点花哨(地图值指向双向链接列表链接),请参阅:
http://code.activestate.com/recipes/576693-ordered-dictionary-for-py24/
我不知道标准库中现有的C ++实现,但这可能会让你在某处。另见:
答案 1 :(得分:2)
unordered_map
是无序的,因此在顺序访问地图时不应指望任何排序。
如果您不希望元素按键值排序,只需使用一个保持插入顺序的容器,无论是vector
,deque
,list
还是其他,如果您坚持使用它,则为pair<key, value>
元素类型。
然后,如果在元素A之后添加了一个快速B,它将始终出现。这适用于initializer_list
初始化。
您可以使用类似Boost.MultiIndex的内容来保持按插入顺序和任意键排序。