unordered_map 中的 C++ 远程键
C++ remote key in unordered_map
我想解决从大文件中删除重复行的问题,使用 std::unordered_map
来存储每行之前是否遇到过的映射。
为了解决文件过大的问题,我希望map中的key是一个std::string
,但是不是为了它存储在内存中,而是在文件是实际存储的值,然后比较器将只读取该位置的一行并与当前键进行比较。
例如,如果字符串是"abcd"
,那么key就是"abcd"
,但是在确定它之前不存在于map中之后,它会被存储为[=15] =] 例如,其中 36
是文件中 "abcd"
的起始位置。
有没有什么方法可以使用内置的 std::unordered_map
(或其他 hashmap 数据结构)而不实现我自己的?
此外,如果没有,我自己实现它的最佳方法是什么?我正在考虑使用 std::unordered_map<size_t, vector<int>>
,其中size_t
键是我的字符串的 std::hash
,向量存储文件中的位置,我可以 readline
与之进行比较。有没有更好的方法?
假设您有 class 命名为 Stuff
,其对象仅存储 size_t
但可以找出实际的文本行(如您所述):
struct Stuff // the naming here is arbitrary and the code illustrative
{
static WhateverYouNeedToReadRealRata same_to_all_stuff;
size_t pos;
std::string getText() const
{
return same_to_all_stuff.read_line_somehow_for(pos);
}
};
然后你写自定义哈希:
struct HashStuff
{
size_t operator()(Stuff const& stuff) const
{
return std::hash<std::string>()(stuff.getText());
}
};
然后你编写自定义比较器:
struct CompareStuff
{
bool operator()(Stuff const& left, Stuff const& right) const
{
return left.getText() == right.getText();
}
};
然后你可以设置你的东西并实例化你的 unordered_set:
Stuff::same_to_all_stuff = yourSpecialCase();
std::unordered_set<Stuff,HashStuff,CompareStuff> stuffSet;
等等 Q.E.D。使用自定义比较器和哈希器是微不足道的吗?
我在这里发布我的解决方案以防它对任何人有帮助。这是基于Oo Tiib
在他上面的回答中给出的想法。
首先是两个类,Line
代表行。
class Line {
streampos pos_;
ifstream &file_;
mutable streampos tpos_;
mutable ios_base::iostate state_;
void SavePos(streampos pos) const {
tpos_ = file_.tellg();
state_ = file_.rdstate();
file_.clear();
file_.seekg(pos);
}
void RestorePos() const {
file_.setstate(state_);
file_.seekg(tpos_);
}
public:
Line(ifstream &f, streampos pos): pos_(pos), file_(f) { }
string GetText() const {
string line;
SavePos(pos_);
getline(file_, line);
RestorePos();
return line;
}
const bool operator==(const Line& other) const {
return (this->GetText() == other.GetText());
}
};
然后,HashLine
仿函数读取该行并将其散列为字符串。
class HashLine {
public:
const size_t operator() (const Line& l) const {
return std::hash<string>()(l.GetText());
}
};
最后是 rm_dups
函数,它创建哈希表并使用上面的 类 删除重复行:
int rm_dups(const string &in_file, const string &out_file) {
string line;
unordered_set<Line, HashLine> lines;
ifstream file(in_file);
ofstream out(out_file);
if (!file || !out) {
return -1;
}
streampos pos = file.tellg();
while (getline(file, line)) {
Line l(file, pos);
if (lines.find(l) == lines.end()) {
// does not exist so far, add this new line
out << l.GetText() << '\n';
lines.insert(l);
}
pos = file.tellg();
}
return 0;
}
我想解决从大文件中删除重复行的问题,使用 std::unordered_map
来存储每行之前是否遇到过的映射。
为了解决文件过大的问题,我希望map中的key是一个std::string
,但是不是为了它存储在内存中,而是在文件是实际存储的值,然后比较器将只读取该位置的一行并与当前键进行比较。
例如,如果字符串是"abcd"
,那么key就是"abcd"
,但是在确定它之前不存在于map中之后,它会被存储为[=15] =] 例如,其中 36
是文件中 "abcd"
的起始位置。
有没有什么方法可以使用内置的 std::unordered_map
(或其他 hashmap 数据结构)而不实现我自己的?
此外,如果没有,我自己实现它的最佳方法是什么?我正在考虑使用 std::unordered_map<size_t, vector<int>>
,其中size_t
键是我的字符串的 std::hash
,向量存储文件中的位置,我可以 readline
与之进行比较。有没有更好的方法?
假设您有 class 命名为 Stuff
,其对象仅存储 size_t
但可以找出实际的文本行(如您所述):
struct Stuff // the naming here is arbitrary and the code illustrative
{
static WhateverYouNeedToReadRealRata same_to_all_stuff;
size_t pos;
std::string getText() const
{
return same_to_all_stuff.read_line_somehow_for(pos);
}
};
然后你写自定义哈希:
struct HashStuff
{
size_t operator()(Stuff const& stuff) const
{
return std::hash<std::string>()(stuff.getText());
}
};
然后你编写自定义比较器:
struct CompareStuff
{
bool operator()(Stuff const& left, Stuff const& right) const
{
return left.getText() == right.getText();
}
};
然后你可以设置你的东西并实例化你的 unordered_set:
Stuff::same_to_all_stuff = yourSpecialCase();
std::unordered_set<Stuff,HashStuff,CompareStuff> stuffSet;
等等 Q.E.D。使用自定义比较器和哈希器是微不足道的吗?
我在这里发布我的解决方案以防它对任何人有帮助。这是基于Oo Tiib
在他上面的回答中给出的想法。
首先是两个类,Line
代表行。
class Line {
streampos pos_;
ifstream &file_;
mutable streampos tpos_;
mutable ios_base::iostate state_;
void SavePos(streampos pos) const {
tpos_ = file_.tellg();
state_ = file_.rdstate();
file_.clear();
file_.seekg(pos);
}
void RestorePos() const {
file_.setstate(state_);
file_.seekg(tpos_);
}
public:
Line(ifstream &f, streampos pos): pos_(pos), file_(f) { }
string GetText() const {
string line;
SavePos(pos_);
getline(file_, line);
RestorePos();
return line;
}
const bool operator==(const Line& other) const {
return (this->GetText() == other.GetText());
}
};
然后,HashLine
仿函数读取该行并将其散列为字符串。
class HashLine {
public:
const size_t operator() (const Line& l) const {
return std::hash<string>()(l.GetText());
}
};
最后是 rm_dups
函数,它创建哈希表并使用上面的 类 删除重复行:
int rm_dups(const string &in_file, const string &out_file) {
string line;
unordered_set<Line, HashLine> lines;
ifstream file(in_file);
ofstream out(out_file);
if (!file || !out) {
return -1;
}
streampos pos = file.tellg();
while (getline(file, line)) {
Line l(file, pos);
if (lines.find(l) == lines.end()) {
// does not exist so far, add this new line
out << l.GetText() << '\n';
lines.insert(l);
}
pos = file.tellg();
}
return 0;
}