我有两个Foo对象列表。每个Foo对象都有一个时间戳Foo.timestamp。两个列表最初按时间戳按降序排序。
我想合并两个Foo对象列表,其中最终列表也按时间戳按降序排序。
实现这一点并不难,但我想知道是否有任何内置的Ruby方法可以做到这一点,因为我认为内置方法将产生最佳性能。
感谢。
答案 0 :(得分:4)
这样可行,但它不会提供很好的性能,因为它不会利用事先已经排序的列表:
list = (list1 + list2).sort_by(&:timestamp)
我不知道任何内置函数能够达到你想要的效果。
答案 1 :(得分:2)
我快速查看了Array#sort
和Enumerable#sort
实施,两者似乎都使用了quicksort。因此,他们可能可能不如您手动使用merge sort那样高效,而a nice article about self-implemented sorting algorithms依次选择两个潜在元素中的哪一个输出到新列表。
然而,Enumerable#sort_by
表明,一个程序员比底层快速排序做得更好的努力失败了 - 他没有直接解决你遇到的问题,但他的数字令人生畏,我尝试了默认{首先排序{3}},只有当感觉太慢时才会返回尝试自编合并排序。
答案 2 :(得分:2)
合并两个臭臭的势在必行...
a = [1,3,7,11]
b = [2,4,6,14]
c = merge_sorted_arrays(a,b)
def merge_sorted_arrays(a,b)
a.reverse!
b.reverse!
output = []
loop do
break if a.empty? || b.empty?
output << (a.last < b.last ? a.pop : b.pop)
end
return output + a.reverse + b.reverse
end
也许正在使用.slice!拿第一个元素会比倒转和弹出更好吗?
====================
第四条评论后编辑:
是的......我还有另一场戏,但需要继续实际工作,否则我会被解雇; - )
在大型整数数组上,我的原始方法比使用sort_by更快,但在使用100,000个OpenStruct对象填充数组并对属性进行排序后,sort_by的速度提高了100倍。
这是我的基准测试结果:
def pop_merge_sorted_arrays(array1,array2)
array1.reverse!
array2.reverse!
output = []
loop do
break if array1.empty? || array2.empty?
output << (array1.last.my_field < array2.last.my_field ? array1.pop : array2.pop)
end
return output + array1.reverse + array2.reverse
end
def shift_merge_sorted_arrays(array1,array2)
output = []
loop do
break if array1.empty? || array2.empty?
output << (array1.first.my_field < array2.first.my_field ? array1.shift : array2.shift)
end
return output + array1 + array2
end
def slice_merge_sorted_arrays(array1,array2)
output = []
loop do
break if array1.empty? || array2.empty?
output << (array1.first.my_field < array2.first.my_field ? array1.slice!(0) : array2.slice!(0))
end
return output + array1 + array2
end
a=(1..100000).map{|x|OpenStruct.new(:my_field => rand)}.sort_by(:my_field)
b=(1..100000).map{|x|OpenStruct.new(:my_field => rand)}.sort_by(:my_field)
# method 1
t=Time.now;w=pop_merge_sorted_arrays(a.clone,b.clone);puts Time.now-t
# average of five runs: 185.96seconds
# method 2
t=Time.now;x=shift_merge_sorted_arrays(a.clone,b.clone);puts Time.now-t
# average of five runs: 0.77seconds
# method 3
t=Time.now;y=slice_merge_sorted_arrays(a.clone,b.clone);puts Time.now-t
# average of five runs: 8.46seconds
# method 4
t=Time.now;z=(a.clone + b.clone).sort_by(&:my_field);puts Time.now-t
# average of five runs: 2.13seconds
所以结果似乎是你可以编写一种方法,在保持秩序运行得非常快的同时将它们洗牌(并且可能会有更多的效率来挤出shift_merge方法,但为了额外的好处,是它真的值得不只是将它们拼凑在一起并使用sort_by以方便它?: - )
我希望这不算是一个题外话......
答案 3 :(得分:0)
使用extend()
方法在list2
的末尾添加list1
:
list1 = ["a", "b" , "c"]
list2 = [1, 2, 3]
list1.extend(list2)
print(list1)