给定一个数组数组
[["B", "C", "E", "F"], ["A", "B", "C", "D"], ["G"]]
合并包含由任意两个或多个数组项共享的成员的数组项的最简单方法是什么。例如,上面应该是
[["A", "B", "C", "D","E", "F"], ["G"]]
因为“B”和“C”由第一个和第二个数组项共享。
以下是一些测试案例。
[["B", "C", "E", "F"], ["A", "B", "C", "D"], ["F", "G"]]
=> [["A", "B", "C", "D", "E", "F", "G"]]
[["B", "C", "E", "F"], ["A", "B", "C", "D"], ["G"], ["G", "H"]]
=> [["A", "B", "C", "D", "E", "F"], ["G", "H,"]]
答案 0 :(得分:2)
这是我的快速版本,可以优化我确定:)
# array = [["B", "C", "E", "F"], ["A", "B", "C", "D"], ["G"]]
# array = [["B", "C", "E", "F"], ["A", "B", "C", "D"], ["F", "G"]]
array = [["B", "C", "E", "F"], ["A", "B", "C", "D"], ["G"], ["G", "H"]]
array.collect! do |e|
t = e
e.each do |f|
array.each do |a|
if a.index(f)
t = t | a
end
end
end
e = t.sort
end
p array.uniq
答案 1 :(得分:1)
修改:Martin DeMello代码已修复。
当运行Martin DeMello代码(接受的答案)时,我得到:
[["B", "C", "E", "F"], ["A", "B", "C", "D"], ["F", "G"]] =>
[["B", "C", "E", "F", "A", "D", "G"], ["A", "B", "C", "D"], ["F", "G"]]
and
[["B", "C", "E", "F"], ["A", "B", "C", "D"], ["G"], ["G", "H"]] =>
[["B", "C", "E", "F", "A", "D"], ["A", "B", "C", "D"], ["G", "H"], ["G", "H"]]
似乎不符合您的规范。
这是我使用他的一些想法的方法:
a = [["B", "C", "E", "F"], ["A", "B", "C", "D"], ["F", "G"]]
b = [["B", "C", "E", "F"], ["A", "B", "C", "D"], ["G"], ["G", "H"]]
def reduce(array)
h = Hash.new {|h,k| h[k] = []}
array.each_with_index do |x, i|
x.each do |j|
h[j] << i
if h[j].size > 1
# merge the two sub arrays
array[h[j][0]].replace((array[h[j][0]] | array[h[j][1]]).sort)
array.delete_at(h[j][1])
return reduce(array)
# recurse until nothing needs to be merged
end
end
end
array
end
puts reduce(a).to_s #[["A", "B", "C", "D", "E", "F", "G"]]
puts reduce(b).to_s #[["A", "B", "C", "D", "E", "F"], ["G", "H"]]
答案 2 :(得分:1)
不同的算法,使用合并即用方法,而不是在数组上进行两次传递(模糊地受联合查找算法的影响)。感谢有趣的问题:)
A = [["A", "G"],["B", "C", "E", "F"], ["A", "B", "C", "D"], ["B"], ["H", "I"]]
H = {}
B = (0...(A.length)).to_a
def merge(i,j)
A[j].each do |e|
if H[e] and H[e] != j
merge(i, H[e])
else
H[e] = i
end
end
A[i] |= A[j]
B[j] = i
end
A.each_with_index do |x, i|
min = A.length
x.each do |j|
if H[j]
merge(H[j], i)
else
H[j] = i
end
end
end
out = B.sort.uniq.map {|i| A[i]}
p out
答案 3 :(得分:0)
不是最简单的,可能是最长的:)
l = [["B", "C", "E", "F"], ["A", "B", "C", "D"], ["G"]]
puts l.flatten.inject([[],[]]) {|r,e| if l.inject(0) {|c,a| if a.include?(e) then c+1 else c end} >= 2 then r[0] << e ; r[0].uniq! else r[1] << e end ; r}.inspect
#[["B", "C"], ["E", "F", "A", "D", "G"]]
答案 4 :(得分:0)
l = [["B", "C", "E", "F"], ["A", "B","C", "D"], ["G"]]
p l.inject([]){|r,e|
r.select{|i|i&e!=[]}==[]&&(r+=[e])||(r=r.map{|i|(i&e)!=nil&&(i|e).sort||i})
}
我不确定你的cond。
答案 5 :(得分:0)
直截了当而不是聪明。它破坏了原始阵列。基本思路是:
它比交叉每对阵列“在算法上更便宜”,但实际的运行速度将取决于红宝石交给C层的东西。
a = [["B", "C", "E", "F"], ["A", "B", "C", "D"], ["G"], ["G", "H"]]
h = Hash.new {|h,k| h[k] = []}
a.each_with_index {|x, i| x.each {|j| h[j] << i}}
b = (0...(a.length)).to_a
h.each_value do |x|
x = x.sort_by {|i| b[i]}
if x.length > 1
x[1..-1].each do |i|
b[i] = [b[i], b[x[0]]].min
a[b[i]] |= a[i]
end
end
end
a = b.sort.uniq.map {|i| a[i]}
答案 6 :(得分:0)
最简单的方法是获取数组的powerset(包含数组元素的每个可能组合的集合),如果它们没有公共元素,则抛出任何结果集,flatten其余的设置和丢弃子集和重复。
或者至少如果Ruby有适当的Set支持。实际上在Ruby中这样做是非常低效的,并且是一个非常糟糕的问题:
power_set = array.inject([[]]){|c,y|r=[];c.each{|i|r<<i;r<<i+[y]};r}.reject{|x| x.empty?}
collected_powerset = power_set.collect{|subset| subset.flatten.uniq.sort unless
subset.inject(subset.last){|acc,a| acc & a}.empty?}.uniq.compact
collected_powerset.reject{|x| collected_powerset.any?{|c| (c & x) == x && x.length < c.length}}
电源设置操作来自here。
答案 7 :(得分:0)
def merge_intersecting(input, result=[])
head = input.first
tail = input[1..-1]
return result if tail.empty?
intersection = tail.select { |arr| !(head & arr).empty? }
unless intersection.empty?
merged = head | intersection.flatten
result << merged.sort
end
merge_intersecting(tail, result)
end
require 'minitest/spec'
require 'minitest/autorun'
describe "" do
it "merges input array" do
input = [["B", "C", "E", "F"], ["A", "B", "C", "D"], ["F", "G"]]
output = [["A", "B", "C", "D", "E", "F", "G"]]
merge_intersecting(input).must_equal output
end
it "merges input array" do
input = [["B", "C", "E", "F"], ["A", "B", "C", "D"], ["G"], ["G", "H"]]
output = [["A", "B", "C", "D", "E", "F"], ["G", "H"]]
merge_intersecting(input).must_equal output
end
end