[英]C++ remote key in unordered_map
我想解決使用std::unordered_map
從大文件中刪除重復行的問題,以存儲先前是否遇到過每行的映射。
為了解決文件太大的問題,我希望映射中的鍵為std::string
但不要將其存儲在內存中,而是將其在文件中的位置作為實際存儲的值 ,然后比較器將只讀取該位置的一行並與當前鍵進行比較。
例如,如果字符串是"abcd"
,那么關鍵將是"abcd"
,但確定它不存在於地圖先前存在后,將它存儲為36
例如,其中36
是的開始位置"abcd"
。
有什么方法可以使用內置的std::unordered_map
(或其他hashmap數據結構) 來執行此操作,而無需自己實現?
另外,如果沒有,我自己實現它的最佳方法是什么? 我當時在考慮使用std::unordered_map<size_t, vector<int>>
,其中size_t
鍵是我字符串的std::hash
,向量將位置存儲在文件中,我可以根據該位置readline
並進行比較。 有沒有更好的辦法?
假設您有一個名為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();
}
};
因此,您可以設置Stuff並實例化unordered_set:
Stuff::same_to_all_stuff = yourSpecialCase();
std::unordered_set<Stuff,HashStuff,CompareStuff> stuffSet;
那么使用自定義比較器和哈希器的QED是微不足道的嗎?
我在這里發布我的解決方案,以防萬一。 這是基於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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.