我有两种形式的数据:
x | y | z x1 | y1 | z1
ab1 | 1 | 2 ab1 | 1 | 2
ab1 | 2 | 3 ab1 | 1.8 | 2
ab2 | 2 | 3 ab1 | 1.8 | 2
列数可以在1到30之间变化。两组的行数可能不同。 每组的平均行数可以在几百到几百万之间变化。 对于每列,将应用不同的匹配规则,例如:
x: perfect match
y: +/- 0.1
z: +/- 0.5
当满足所有标准时,两行是等效的。 我的最终目标是在第二组中找到第二组中没有匹配的行。
天真的算法可能是:
foreach a in SetA
{
foreach b in SetB
{
if (a == b)
{
remove b from SetB
process the next element in SetA
}
}
log a is not in SetB
}
在这个阶段,我对算法的效率不是很感兴趣。我相信我可以做得更好,我可以降低复杂性。 我更关心结果的正确性。让我们试试一个非常简单的例子。 两组数字:
A B
1.6 1.55
1.5 1.45
4 3.2
如果符合以下两个要素:
b + 0.1 >= a >= b - 0.1
现在,如果我运行朴素算法,我将找到2个匹配项。 然而,算法的结果取决于两组的顺序。例如:
A B
1.5 1.55
1.6 1.45
4 3.2
该算法只能找到一个匹配。
我想找到最大匹配行数。
我认为在真实世界中,其中一列会存储一个id,因此可能的多个匹配的数量将是原始集的一个小得多的子集。 我知道我可以尝试在第一次扫描后通过后处理来解决这个问题。 但是,我不想重新发明轮子,我想知道我的问题是否等同于一些着名的,众所周知的,已经解决的问题。
PS:我已将问题标记为C ++,C#和Java,因为我将使用其中一种语言来实现它。
答案 0 :(得分:1)
它可以被视为图论问题。设X是一个包含第一组中每行的一个节点的集合。设Y为另一组,其中包含第二组中每行的一个节点。
图中的边界定义为:对于X中的给定x和Y中的给定y,如果对应于x的行与对应于y的行匹配,则存在边(x,y)。
构建此图表后,您可以在其上运行“maximum-bipartite-matching”算法,您将完成。
答案 1 :(得分:1)
据我所知,您希望第一组中的行与第二组中的任何行匹配(在错误范围内)。通过解析第一组中的元素并将它们与第二组中的元素进行比较,可以使用O(n ^ 2)复杂度算法来实现这种清晰度。 优化可能是这样的:
对两个集合进行排序 - O(n * ln(n))
从头开始消除第一组中的元素太小或太大(在错误内) - O(n)
使用二分搜索(在错误内)查看第一组元素的第二组 - O(n * lg(2))并消除那些不合适的
comlexity O(n * ln(n))
答案 2 :(得分:0)
范围树? http://en.wikipedia.org/wiki/Range_tree 我真的不知道,只是把想法扔出去
答案 3 :(得分:0)
从声明“我的最终目标是找到第一组中的第二组中没有匹配的行”。据我所知,第一组中可能有多行与第二组中的同一行匹配。在这种情况下,解决方案是从您的朴素算法中删除“从SetB中删除b”这一行。
但是,如果你真的需要在两组元素之间进行一对一的匹配,那么Corey Kosak提供的“最大二分匹配”答案就适用了。
答案 4 :(得分:0)
Two rows are equivalent when all the criteria are satisfied. My final goal is to find the rows in the first set with no match in second set.
foreach a in SetA
{
foreach b in SetB
{
if (a == b) //why would you alter SetB at all
go to next A
}
remove a from SetA //log a is not in SetB
}
但是,你是对的,is equivalent to some famous, well known and already solved problem
。它被称为“设置差异”。它是集合论的一个主要部分。由于所有这些语言都有集合,因此它们也具有该算法。 C ++甚至还有一个专用的功能。所有这些的近似复杂度为O(2(A+B)-1)
。
C ++标准算法函数:http://www.cplusplus.com/reference/algorithm/set_difference/
vector<row> Result(A.rows());
end = std::set_difference(A.begin(), A.end(),
B.begin(), B.end(),
Result.begin());
Result.resize(end-Result.begin());
可以使用或std :: unordered_set执行此操作:http://msdn.microsoft.com/en-us/library/bb982739.aspx
std::unordered_set<row> Result(A.begin(), A.end());
for(auto i=B.begin(); i!=B.end(); ++i) {
auto f = Result.find(*i);
if (f != A.end())
A.erase(f);
}
Java也是如此:http://download.oracle.com/javase/tutorial/collections/interfaces/set.html
Set<row> Result = new Set<row>(A);
A.removeAll(B);
和C#:http://msdn.microsoft.com/en-us/library/bb299875.aspx
HashSet<row> Result = new HashSet<row>(A);
A.ExceptWith(B);
答案 5 :(得分:0)
考虑到你的约束,我没有看到一种方法在低于O(n ^ 2)的情况下做到这一点。我可能会修改你的朴素算法,为表A中的每一行包含bool或count字段,然后如果它与表B中的行匹配则标记它。 然后基于指标使用std :: partition对其进行处理,以将所有唯一行和非唯一行组合在一起。如果你计算,你可以获得“最不唯一”的行。因为你可以在第一场比赛中突破B圈,所以bool会更有效率。