[英]Inserting into an unordered_set with custom hash function
我有以下代碼來制作unordered_set<Interval>
。 編譯好了。
struct Interval {
unsigned int begin;
unsigned int end;
bool updated; //true if concat. initially false
int patternIndex; //pattern index. valid for single pattern
int proteinIndex; //protein index. for retrieving the pattern
};
struct Hash {
size_t operator()(const Interval &interval);
};
size_t Hash::operator()(const Interval &interval){
string temp = to_string(interval.begin) + to_string(interval.end) + to_string(interval.proteinIndex);
return hash<string>()(temp);
}
unordered_set<Interval, string, Hash> test;
但是,當我嘗試使用此代碼插入時,我無法編譯:
for(list<Interval>::iterator i = concat.begin(); i != concat.end(); ++i){
test.insert((*i));
}
而且,我無法確定錯誤消息的問題,例如:
note: candidate is:
note: size_t Hash::operator()(const Interval&)
note: candidate expects 1 argument, 2 provided
我以為我只提供了一個論點......
我的插入代碼有什么問題?
這是新的實例化代碼: unordered_set<Interval, Hash> test;
但是,我仍然收到大量錯誤消息,例如:
note: candidate is:
note: size_t Hash::operator()(const Interval&) <near match>
note: no known conversion for implicit ‘this’ parameter from ‘const Hash*’ to ‘Hash*’
第一個問題:
您正在傳遞string
作為實例化unordered_set<>
類模板的第二個模板參數。 第二個參數應該是hasher仿函數的類型 ,而std::string
不是可調用對象。
或許打算寫:
unordered_set<Interval, /* string */ Hash> test;
// ^^^^^^^^^^^^
// Why this?
另外,我建議使用begin
和end
以外的名稱作為(成員)變量,因為這些是C ++標准庫的算法名稱。
第二個問題:
你應該記住, hasher函數應該被限定為const
,所以你的函子應該是:
struct Hash {
size_t operator() (const Interval &interval) const {
// ^^^^^
// Don't forget this!
string temp = to_string(interval.b) +
to_string(interval.e) +
to_string(interval.proteinIndex);
return (temp.length());
}
};
第三個問題:
最后,如果您希望std::unordered_set
能夠使用Interval
類型的對象,則需要定義與哈希函數一致的相等運算符。 默認情況下,如果未指定任何類型參數作為std::unordered_set
類模板的第三個參數,則將使用operator ==
。
您目前沒有為您的類Interval
重載operator ==
,因此您應該提供一個。 例如:
inline bool operator == (Interval const& lhs, Interval const& rhs)
{
return (lhs.b == rhs.b) &&
(lhs.e == rhs.e) &&
(lhs.proteinIndex == rhs.proteinIndex);
}
結論:
完成上述所有修改后,您可以在此實例中看到您的代碼編譯。
我認為,Andy Prowl完美地解決了代碼中存在的問題 。 但是,我會在Interval
添加以下成員函數,它描述了兩個區間相同的原因:
std::string getID() const { return std::to_string(b) + " " + std::to_string(e) + " " + std::to_string(proteinIndex); }
請注意,我也跟着安迪四處尋覓的建議,並改名為成員begin
到b
,並end
以e
。 接下來,您可以使用lambda表達式輕松定義哈希和比較函數。 因此,您可以按如下方式定義unordered_set
:
auto hash = [](const Interval& i){ return std::hash<std::string>()(i.getID()); };
auto equal = [](const Interval& i1, const Interval& i2){ return i1.getID() == i2.getID(); };
std::unordered_set<Interval, decltype(hash), decltype(equal)> test(8, hash, equal);
最后,出於可讀性的原因,我將for
循環轉換for
基於范圍的for
循環:
std::list<Interval> concat {{1, 2, false, 3, 4}, {2, 3, false, 4, 5}, {1, 2, true, 7, 4}};
for (auto const &i : concat)
test.insert(i);
for (auto const &i : test)
std::cout << i.b << ", " << i.e << ", " << i.updated << std::endl;
輸出(我剛剛打印了每個Interval
前三個成員):
2,3,0
1,2,0
如您所見,只打印了兩個間隔。 第三個( {1, 2, true, 7, 4}
proteinIndex
{1, 2, true, 7, 4}
)沒有插入到concat
,因為它的b
, e
和proteinIndex
等於第一個區間的值( {1, 2, false, 3, 4}
)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.