为什么"std::unordered_map""speak like the Yoda" - 重新排列元素?
Why does `std::unordered_map` "speak like the Yoda" - re-arrange elements?
在以下示例中尝试写入std::unordered_map
的std::string
密钥时,密钥的写入顺序与初始值设定项列表给出的顺序不同:
#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;
}
我本想看到"我为什么被排序",但我得到了一个类似Yoda的输出:
sorted I am Why
在这里阅读unordered_map
,我看到了这个:
在内部,元素不按任何特定顺序排序,而是组织到存储桶中。元素被放入哪个bucket完全取决于其密钥的散列。这允许快速访问各个元素,因为一旦计算出哈希,它就指的是元素所在的确切桶。
这就是为什么元素的排序方式与初始值设定项列表中的不同吗?
当我希望键以与初始值设定项列表相同的方式排序时,我应该使用什么数据结构?我是否应该在内部保留一个字符串向量,以某种方式保存参数顺序?是否可以通过选择特定的哈希函数以某种方式关闭bucket组织?
当我希望键以与初始值设定项列表相同的方式排序时,我应该使用什么数据结构?我是否应该在内部保留一个字符串向量,以某种方式保存参数顺序?
也许你想要的只是一个(键,值)对的列表/向量?
如果您希望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++实现,但这可能会让你有所收获。另请参阅:
- 一个保留插入顺序的C++哈希映射
- 一个跟踪插入顺序的std::映射
unordered_map
根据定义是无序的,因此在按顺序访问映射时,不应期望任何排序。
如果你不想让元素按键值排序,只要使用一个容器来保持你的插入顺序,无论是vector
、deque
、list
还是其他什么,如果你坚持使用pair<key, value>
元素类型。
然后,如果在元素A之后添加一个元素B,它总是会在后面出现。initializer_list
初始化也是如此。
你可能会使用类似Boost的东西。MultiIndex使其同时按插入顺序和任意键进行排序。
- 如何将元素从向量转移到新数组?
- C++:添加新结构时,结构指针向量中的所有元素都会更新
- 如何在新数组较小时创建新数组并将旧数组的最后一个元素复制到新数组中?
- 静态堆栈函数不会 1) 输入第一个元素 2)添加新元素时识别旧元素
- 在二叉搜索树中插入新元素
- 如何输入数组的元素,每次获得新元素时,我们将其放在数组的中间?
- 将新元素添加到列表中,并返回对该元素的引用?
- 如果键不存在,使用 [] 运算符访问 STL Map 元素会添加新元素
- 向 std::list 添加新元素的复杂性
- 是否可以使用OpenMP并行化一个列表,该列表可以在每次迭代中添加新元素
- r-在Rcpp和C++之间转换矢量(使用Rcpp::as或Rcpp:::wrap)是否会创建一个新的矢量并复制元素
- 如何将 std::vector 的某些元素移动到向量中的新索引?
- 在指向对象的指针的动态数组上插入新元素
- c++ 向量push_back移动新元素
- 为什么"std::unordered_map""speak like the Yoda" - 重新排列元素?
- 从数组中删除零,并根据新的元素数量调整数组大小
- 跳过C++中的排列元素
- GStreatermm:通过从Gst::element派生创建一个新的元素类型(在插件中)
- 是否可以保存std::list中新插入元素的迭代器,然后使用该迭代器安全地擦除该元素?
- c++在Unix编译器上清除字符串中的Windows新行元素