我有兩個Foo對象列表。每個Foo對象都有一個時間戳Foo.timestamp。兩個列表最初都按照時間戳降序排列。內置方法來合併ruby中的兩個排序列表
我想合併兩個Foo對象的列表,最終列表也按時間戳按降序排序。
實現這一點並不難,但我想知道是否有任何內置的Ruby方法可以做到這一點,因爲我認爲內置方法會產生最佳性能。
謝謝。
我有兩個Foo對象列表。每個Foo對象都有一個時間戳Foo.timestamp。兩個列表最初都按照時間戳降序排列。內置方法來合併ruby中的兩個排序列表
我想合併兩個Foo對象的列表,最終列表也按時間戳按降序排序。
實現這一點並不難,但我想知道是否有任何內置的Ruby方法可以做到這一點,因爲我認爲內置方法會產生最佳性能。
謝謝。
這是可行的,但它不會給出色的性能,因爲它不會花費已經預先被排序的名單優勢:
list = (list1 + list2).sort_by(&:timestamp)
我不知道任何內置的函數,它的你想要什麼。
我快速查看了Array#sort
和Enumerable#sort
的實現,並且兩者似乎都使用了quicksort。因此,他們可能不如您手動使用merge sort那樣有效,它會依次選擇將兩個潛在元素中的哪一個輸出到新列表。
然而,a nice article about self-implemented sorting algorithms表明,一個程序員的努力做多標的快速排序更好的悲慘地失敗了 - 他沒有直接接近你有問題,但他的數字是令人望而生畏,以至於我想嘗試的默認排序Enumerable#sort_by
第一,只有當感覺太慢時,我纔會回到嘗試自我合併排序。
合併兩個臭勢在必行過程...
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方法,但對於額外的好處,是不是真的值得不只是bunging在一起,並使用sort_by爲了便於呢?:-)
我希望這並不算是題外話了.. 。
OP說「實現這個並不難」,所以我不認爲他是在要求你爲他實現它。另外,您應該能夠避免四次調用「反向」。 –
a)是的......我建議倒車並不是很好(即使曾經是零陣列但仍然很臭)。我主要是使用代碼作爲一個起點,可能暗示將兩者混洗在一起,而不需要再次調用。 b)我忽略了OP中的「這不難......」。哎呀 - 如果我注意到了,我可能不會發布,但是我注意到你實現了一個不太困難的解決方案;-) – Pavling
FWIW:我剛剛有一些粗糙的基準 - 在兩個上使用「.sort_by」隨機數填充的100,000個元素數組在這裏需要大約0.7秒。如上所述使用四個「反向」調用,同樣的動作大約需要0.3秒。刪除反轉,並用.slice!(0)替換.pop花費7秒以上。在現實生活中 - sort_by或排序可能會很簡單,以保持一行,而不是太擔心:-) – Pavling