我有一个很大的"站点列表,"说350,000左右。这些站来自五个不同的来源,每个都有特定的信息。例如,它们每个都具有五种不同类型的标识符中的至少一种。目标是合并相等的站点(如果站点具有匹配的标识符,则站点相等)。
示例:如果stationA具有identifierA:01234,identifierB:NULL和identifierC:KAKW,并且stationB具有identiferA:NULL,identifierB:USA00012和identifierC:KAKW,我想将它们合并为具有identifierA的新站点:01234 ,identifierB:USA00012,和identifierC:KAKW。
现在我将所有电台都放在一个大矢量中。我一次将一个站点移动到新的vectior中1)如果它不匹配向量中已经存在的任何站点则将其推回,或者2)如果匹配则合并它。
这花费了太多时间。从理论上讲,我可以使用一种有效的算法或概念来加速这个过程吗?我最后一次这样做了将近3天。
答案 0 :(得分:0)
创建3份数据副本,每份副本按不同的标识符排序。
然后选择一个,迭代,并在已排序的容器中查找匹配项。构建组合对象并将其保存到"已处理的"矢量。
答案 1 :(得分:0)
它似乎它应该是一个哈希表-y类型的问题,但也许它不是,因为两个站点的方法不止一种
如果你能省下记忆,我会建议类似阿米特的回答。只需要5个std::map
个标识符容器作为主容器(如数据库)的索引,然后以这种方式进行搜索。有一些前期工作将标识符放入已排序的容器中,但最终可能会更快。
如果您不关心哪个标识符匹配哪个,或者您的标识符数据集不相交,您可以使用一个容器,其中所有五个标识符一起排列(可能是哈希值,但不包括NULL,大概),并搜索。
答案 2 :(得分:0)
下面的代码会对站点进行传递,从而有效地生成站点所具有的标识符的位掩码。它翻转这些位以创建一个位掩码,只有缺少标识符的另一个站将具有该位掩码,并且如果已知这样的站与它合并,则将合并的站添加到稍后要擦除的列表中。否则,它会将不匹配的工作站添加到具有特定位掩码的工作站列表中,以便以后可以快速找到它。 (很少进行测试。)
#include <iostream>
#include <string>
#include <vector>
struct Station
{
int idn_map() const { return 16 * bool(ia_[0]) +
8 * bool(ib_[0]) +
4 * bool(ic_[0]) +
2 * bool(id_[0]) +
bool(ie_[0]); }
void merge(const Station& rhs)
{
if (ia_.empty()) ia_ = rhs.ia_;
if (ib_.empty()) ib_ = rhs.ib_;
if (ic_.empty()) ic_ = rhs.ic_;
if (id_.empty()) id_ = rhs.id_;
if (ie_.empty()) ie_ = rhs.ie_;
}
std::string ia_, ib_, ic_, id_, ie_;
};
std::ostream& operator<<(std::ostream& os, const Station& s)
{
return os << s.ia_ << ':' << s.ib_ << ':' << s.ic_ << ':' << s.id_ << ':' << s.ie_;
}
int main()
{
std::vector<Station> stations = {
{ "s0a", "", "s0c", "", "s0e" },
{ "", "", "s1c", "s1d", "s1e" },
{ "", "s2b", "", "s2d", "" },
{ "s3a", "s3b", "s3c", "s3d", "" },
{ "s4a", "s4b", "", "", "" }
};
std::vector<Station*> unmatched[32];
std::vector<Station*> to_erase;
for (Station& s : stations)
{
int idn_map = s.idn_map();
if (unmatched[idn_map ^ 31].empty())
unmatched[idn_map].push_back(&s);
else
{
// merge from current element so to_erase kept sorted
// for fast compact/erase later...
Station* p_merge_to = unmatched[idn_map ^ 31].back();
p_merge_to->merge(s);
to_erase.push_back(&s);
unmatched[idn_map ^ 31].pop_back();
}
}
for (const auto& p : to_erase)
std::cout << "will remove element at " << p << '\n';
// now compact over the deferred erasures...
auto erase_it = to_erase.begin();
auto to = stations.begin();
for (auto from = to; from != stations.end(); ++from)
if (erase_it != to_erase.end() && *erase_it == &*from)
++erase_it;
else
*to++ = *from;
stations.erase(to, stations.end());
std::cout << "results:\n";
for (const auto& station : stations)
std::cout << station << '\n';
}
代码可用/可运行here。
(在我修正循环逻辑时进行了几次编辑,从使用集合更改为向量以提高性能)