比较它们之间的元素并获取共同值的键

Posted

技术标签:

【中文标题】比较它们之间的元素并获取共同值的键【英文标题】:Compare elements between them and get the keys of common values 【发布时间】:2018-09-26 22:31:45 【问题描述】:

我在两个不同的集合中有成对的数据、键和值。我需要比较两个集合的值,并创建一个包含相等值的键对的集合。

例如,使用以下数据集:

      Vals
Key Col1 Col2
1    4     5
2    6     9
4    8     4
6    10    10

常见的值是 4 和 10。所以他的想法是用这些对获得一个新集合,在这种情况下是 (key col1, key col2) 1, 4, 6, 6

我需要一种最快的方法来做到这一点,每个集合可以有 100k 的数据,并且使用 for 循环进行迭代太慢,我尝试使用向量。

两个集合不一定有相同的键(如 map),数据可能不是 int (我使用二进制数据,通常键是 int(unsinged long)。

这是我的示例代码(非常慢的代码):

struct p 
    unsigned long int p1;
    unsigned long int p2;
;

vector<int> table1 = tables1(n); /* bigger n -> more samples */
vector<int> table2 = tables2(n); /* n = 10000 generate 150k per table */

vector<p> common;

for (unsigned long int i = 0;i < table1.size(); i++) 
    for (unsigned long int j = 0; j < table2.size(); j++) 
        if (table1[i] == table2[j]) common.push_back (i, j;
    

有没有办法用地图、集合或其他东西更快地做到这一点? (我从 C++ 开始)

【问题讨论】:

创建两张地图。 A 从键映射到 col1,B 从键映射到 col2。然后只比较 A[key] == B[key] 如果 key 存在于两者中 你的意思是用map而不是vector做同样的事情?,在那种情况下我认为不会更快,这个算法真的很慢...... 应该是 O(n lgn) 而不是 O(n^2) 测试了一下,还是很慢...,比较地图或者矢量图..... 那你做得不对。正确的算法将同时遍历两个映射,而不是遍历第一个映射,然后每次都检查第二个映射。这是错误的。您需要同时遍历两个地图。如果你还有问题,你应该向你的老师寻求帮助,也就是给你这个作业的那个人。这就是教师的报酬,帮助学生完成家庭作业。 【参考方案1】:

实际上,您比较了它们之间的所有值,并想知道每个集合中该值的键。

在这种情况下,我建议简单地反转每个映射中的键和值。这将导致以下结构:

      Vals
RevKey1 RevVal1 RevKey2 RevVal2
4       1         5     1
6       2         9     2
8       4         4     4
10      6        10     6

然后您只需遍历第一个映射,并在第二个映射中查找相同的键:

map<int,int> col1;
map<int,int> col2;
map<int,pair<int,int>> common ; 
...
for (auto& x: col1) 
    auto y= col2.find(x.first); 
    if (y!=col2.end()) 
        common[x.first]=make_pair(x.second,y->second);

cout<<"Result:"<<endl;
for (auto& x:common ) 
    cout << x.first << "<-" << x.second.first << " in col1 and " <<x.second.second << " in col2"<<endl;

Online demo

备注:我让您作为练习,对现有地图中表达的映射关系进行反演。我还让你扩展这个算法来处理多映射,以防多个键具有相同的值。

【讨论】:

为什么需要两张地图? @PaulSanders 我使用了地图,因为 OP 的数据显示键不连续。例如没有键 3。使用vector&lt;int&gt; 你不能代表这个。此外,OP 建议数据可能与整数不同,这在地图的情况下不是问题。 感谢您的回答,似乎没有内置函数(考虑不同长度的表),这会更好,我知道如何反转地图,但使用 multimap 是对我来说是新的,那将是我的练习,谢谢帮助:D【参考方案2】:

下面的(非常简单的)代码似乎可以解决问题:

#include <map>
#include <vector>
#include <iostream>

struct p

    p (int p1, int p2) : p1 (p1), p2 (p2)  
    int p1;
    int p2;
;

std::vector<int> table1;
std::vector<int> table2;
std::vector<p> common;

#define N   100000

int main ()

    table1.reserve (N);
    table2.reserve (N);

    for (int i = 0; i < N; ++i)
        table1.emplace_back (rand ());

    for (int i = 0; i < N; ++i)
        table2.emplace_back (rand ());

    std::map <int, int> map1;
    for (int i = 0; i < N; ++i)
        map1 [table1 [i]] = i;

    common.reserve (N);

    int n = table2.size();
    for (int i = 0; i < n; i++)
    
        auto f = map1.find (table2 [i]);
        if (f != map1.end ())
            common.emplace_back (i, f->second);
    

    for (auto x : common)
       std::cout << x.p1 << ", " << x.p2 << "\n";

输出:

12727, 93810
12766, 48493
16044, 71990
43202, 35849
46218, 81007
82512, 70112
98740, 72244

注意reserveemplace_back 用于向量。

在Wandbox运行它

我尝试将 N 增加到 1000000,但它仍然有效。无序(散列)地图可能会更快。

【讨论】:

以上是关于比较它们之间的元素并获取共同值的键的主要内容,如果未能解决你的问题,请参考以下文章

获取值的键而不是获取键值? [复制]

php数组操作之获取数组元素索引(键)值

JS以字符串开头的键获取对象的值

获取 PL/SQL 集合中特定元素的键或索引?

比较两个字符串并返回它们之间的共同字符?

PHP获取数组中重复值的键值