簡體   English   中英

unordered_map中的C ++遠程密鑰

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM