Ruby on rails 匹配具有最大相似性的2个哈希的有效方法
有没有一种有效的方法可以找到两个id 类似选项\u ID的最大数量 上述例子的答案是Ruby on rails 匹配具有最大相似性的2个哈希的有效方法,ruby-on-rails,ruby,algorithm,hashmap,ruby-hash,Ruby On Rails,Ruby,Algorithm,Hashmap,Ruby Hash,有没有一种有效的方法可以找到两个id 类似选项\u ID的最大数量 上述例子的答案是 [[1148612624],[1458814590] 我已经尝试过的是- 获取每个散列并将其opt_id与数组中其他剩余散列的opt_id进行比较 当前哈希的opt_id与这2个id中最匹配的哈希 因此,我在每个散列上循环的次数与数组中散列的次数相同-O(n^2) 您可以检查数组中的差异。所以,如果它返回空数组,或者说元素数较少,则表示它们相等或几乎相等 例如: [ {"id"=>
[[1148612624],[1458814590]
我已经尝试过的是-
opt_id
与数组中其他剩余散列的opt_id
进行比较O(n^2)
您可以检查数组中的差异。所以,如果它返回空数组,或者说元素数较少,则表示它们相等或几乎相等 例如:
[
{"id"=>11486, "opt_ids"=> [3545, 3546, 3548, 3550] },
{"id"=>12624, "opt_ids"=> [3545, 3396, 3548, 3550] },
{"id"=>14588, "opt_ids"=> [3394, 3396, 3397, 3399] },
{"id"=>14589, "opt_ids"=> [3394, 3545, 3398, 3548] },
{"id"=>14590, "opt_ids"=> [3394, 3396, 3397, 3399, 3545, 3547, 3548, 3551, 3653, 3655, 3657, 3660, 3772, 3775, 3777, 3778]},
.....
.....
...
...
]
假设我们得到一个非负整数
max_diff
,这样两个整数,n1
和n2
被视为“相似”,如果
并具体说明:
arr = [
{ "id"=>11486, "opt_ids"=> [3545, 3546, 3548, 3550] },
{ "id"=>12624, "opt_ids"=> [3545, 3396, 3548, 3550] },
{ "id"=>14588, "opt_ids"=> [3394, 3396, 3397, 3399] },
{ "id"=>14589, "opt_ids"=> [3394, 3545, 3398, 3548] },
{ "id"=>14590, "opt_ids"=> [3394, 3396, 3397, 3399] },
{ "id"=>14591, "opt_ids"=> [3545, 3547, 3548, 3551] },
{ "id"=>14592, "opt_ids"=> [3653, 3655, 3657, 3660] },
{ "id"=>14593, "opt_ids"=> [3772, 3775, 3777, 3778] }
]
我将假设我们将根据元素对的计数对这些散列(以及与“id”
相关的值对)进行排序[h1[“opt_id”][I],h2[“opt_id”][j]]
,它们在我上面的定义中是“相似的”。这可能与您的想法不一致,但它可能是一个有用的起点。我简要介绍了max_diff
始终为零的情况
考虑哈希值
arr[0]
和arr[3]
的“opt_id”
值:
max_diff = 3
如下表所示,a0
中的3545
类似于a3
的两个元素,3545
和3548
。类似地,a0
中的3546
、3548
和3550
分别类似于2
、2
和1
元素a3
,这意味着散列arr[0]
和arr[3]
可以被认为具有7
的相似性分数
a0 = arr[0]["opt_ids"]
#=> [3545, 3546, 3548, 3550]
a3 = arr[3]["opt_ids"]
#=> [3394, 3545, 3398, 3548]
我们可以使用以下帮助器方法实现此计数
a0 a3 #
____________________
3545: 3545, 3548 (2)
3546: 3545, 3548 (2)
3548: 3545, 3548 (2)
3550: 3548 (1)
如果我误解了这个问题,并且
max_diff
始终为零,并且如果所有数组arr[I][“opt_id”]
都包含唯一的元素(就像问题中的示例中那样),则可以编写
count_similar(a0, a3, max_diff)
#=> 7
并删除max_diff
参数
我们现在可以按如下方式计算成对ID的相似性度量:
def count_similar(a1, a2)
(a1 & a2).size
end
然后,我们可以计算这样的度量,以确定五对具有最高相似性分数的组合:
similarities(arr, max_diff)
#=> {[11486, 12624]=> 9, [11486, 14588]=>0, [11486, 14589]=> 7, [11486, 14590]=>0,
# [11486, 14591]=>13, [11486, 14592]=>0, [11486, 14593]=> 0, [12624, 14588]=>4,
# [12624, 14589]=> 7, [12624, 14590]=>4, [12624, 14591]=>10, [12624, 14592]=>0,
# [12624, 14593]=> 0, [14588, 14589]=>6, [14588, 14590]=>14, [14588, 14591]=>0,
# [14588, 14592]=> 0, [14588, 14593]=>0, [14589, 14590]=> 6, [14589, 14591]=>7,
# [14589, 14592]=> 0, [14589, 14593]=>0, [14590, 14591]=> 0, [14590, 14592]=>0,
# [14590, 14593]=> 0, [14591, 14592]=>0, [14591, 14593]=> 0, [14592, 14593]=>0}
这表明这对ID,14588
和14590
(来自arr[2]
和arr[4]
)的相似性得分最高,为14
我把表格放在这里,上面有相同的数据。我从许多不同的表中创建了一个视图
用SQL来做,这就是它擅长的
使用自联接获取每对的重叠数
similarities(arr, max_diff).max_by(5, &:last)
#=> [[[14588, 14590], 14], [[11486, 14591], 13], [[12624, 14591], 10],
# [[11486, 12624], 9], [[12624, 14589], 7]]
即使没有索引,它的性能也应该比把它全部放到Ruby中要好得多。对于上面的例子,答案是什么?你试过什么?“循环”很模糊。@Schwern谢谢你的提问,我已经更新了我的问题。请让我知道现在是否更清楚?是的,谢谢。您有多少数据?数据多久更改一次?你想要什么样的表演?将其放入SQLite可能是有意义的。@Schwern此数据已经是数据库的一部分,我已经从那里聚合了它。目前,数组中的哈希数可以在50到500之间变化。我想要的性能是,为了根据最大相似选项id匹配2个id,我不必循环遍历每个哈希。选项ID的数量每周都会增加。在SQL中这样做可能更容易、更快。你能给我看一下原始的表格吗?没错,但我还是得把a和b、c、d一一比较一下。尽量避免这种情况。不过数组的长度不同。所以一个空的差异并不意味着什么:
a-b#=>[]
可能仅仅意味着a
是空的。设置交叉点(&
)可能是一个更好的主意。谢谢你的回答,让我分析一下,然后返回。谢谢你的回答,让我分析一下,然后返回。谢谢你在这个方向上指导我,尽管有点不同。它帮助我有了另一个视角@cary
with overlaps as (
select
a.emp_id emp_id1,
b.emp_id emp_id2,
count(a.option_id) as overlap
from data a
join data b on
a.emp_id < b.emp_id and
a.option_id = b.option_id
group by a.emp_id, b.emp_id
)
select *
from overlaps
where overlap = (
select max(overlap)
from overlaps
)
def similarities(arr, max_diff)
arr.combination(2)
.map do |h1,h2|
[[h1["id"], h2["id"]],
count_similar(h1["opt_ids"], h2["opt_ids"], max_diff)]
end.to_h
end
similarities(arr, max_diff)
#=> {[11486, 12624]=> 9, [11486, 14588]=>0, [11486, 14589]=> 7, [11486, 14590]=>0,
# [11486, 14591]=>13, [11486, 14592]=>0, [11486, 14593]=> 0, [12624, 14588]=>4,
# [12624, 14589]=> 7, [12624, 14590]=>4, [12624, 14591]=>10, [12624, 14592]=>0,
# [12624, 14593]=> 0, [14588, 14589]=>6, [14588, 14590]=>14, [14588, 14591]=>0,
# [14588, 14592]=> 0, [14588, 14593]=>0, [14589, 14590]=> 6, [14589, 14591]=>7,
# [14589, 14592]=> 0, [14589, 14593]=>0, [14590, 14591]=> 0, [14590, 14592]=>0,
# [14590, 14593]=> 0, [14591, 14592]=>0, [14591, 14593]=> 0, [14592, 14593]=>0}
similarities(arr, max_diff).max_by(5, &:last)
#=> [[[14588, 14590], 14], [[11486, 14591], 13], [[12624, 14591], 10],
# [[11486, 12624], 9], [[12624, 14589], 7]]
select
a.emp_id emp_id1,
b.emp_id emp_id2,
count(a.option_id) as overlap
from data a
join data b on
-- Ensure we count each pair only once
a.emp_id < b.emp_id and
a.option_id = b.option_id
group by a.emp_id, b.emp_id
with overlaps as (
select
a.emp_id emp_id1,
b.emp_id emp_id2,
count(a.option_id) as overlap
from data a
join data b on
a.emp_id < b.emp_id and
a.option_id = b.option_id
group by a.emp_id, b.emp_id
)
select *
from overlaps
where overlap = (
select max(overlap)
from overlaps
)
create index idx_option_emp_ids on data(option_id, emp_id);