2010-02-11 122 views
35

我有兩個數組我需要合併,並使用聯合(|)運算符PAINFULLY慢..有沒有其他方法來完成數組合並?數組合並(聯合)

另外,數組中填充了對象而不是字符串。

陣列

#<Article 
id: 1, 
xml_document_id: 1, 
source: "<article><domain>events.waikato.ac</domain><excerpt...", 
created_at: "2010-02-11 01:32:46", 
updated_at: "2010-02-11 01:41:28" 
> 

當源是一小段的XML中的對象的一個​​實例。

編輯

對不起! 「合併」我的意思是我不需要插入重複。

A => [1, 2, 3, 4, 5] 
B => [3, 4, 5, 6, 7] 
A.magic_merge(B) #=> [1, 2, 3, 4, 5, 6, 7] 

瞭解,該整數實際上是Article對象,並聯合運營商似乎採取永遠

+0

你是什麼意思合併?你將如何處理對象身份和內容的差異? – 2010-02-11 03:30:38

+0

我不知道,我想我正在尋找的是一種'合併'的方式,並有一個比較運算符來比較對象來合併時間。 – Rabbott 2010-02-11 03:43:10

+0

Ryan:這是一個有趣的問題,但我認爲如果您投票選出對您有幫助的答案並接受每個問題的最佳答案,您會在本網站上獲得更多/更好的答案。這是Stack Overflow的基本貨幣,當人們看到他們接受的唯一答案是他們自己的答案時,人們會很小心地幫助別人。 – 2010-02-11 16:40:11

回答

61

下面是一個基準測試兩種合併技巧的腳本:使用管道運算符(a1 | a2),並使用concatenate-and-uniq((a1 + a2).uniq)。兩個額外的基準分別給出了concatenate和uniq的時間。

require 'benchmark' 

a1 = []; a2 = [] 
[a1, a2].each do |a| 
    1000000.times { a << rand(999999) } 
end 

puts "Merge with pipe:" 
puts Benchmark.measure { a1 | a2 } 

puts "Merge with concat and uniq:" 
puts Benchmark.measure { (a1 + a2).uniq } 

puts "Concat only:" 
puts Benchmark.measure { a1 + a2 } 

puts "Uniq only:" 
b = a1 + a2 
puts Benchmark.measure { b.uniq } 

在我的機器(Ubuntu的業報,紅寶石1.8.7),我得到這樣的輸出:

Merge with pipe: 
    1.000000 0.030000 1.030000 ( 1.020562) 
Merge with concat and uniq: 
    1.070000 0.000000 1.070000 ( 1.071448) 
Concat only: 
    0.010000 0.000000 0.010000 ( 0.005888) 
Uniq only: 
    0.980000 0.000000 0.980000 ( 0.981700) 

這表明,這兩種技術在速度上非常相似,並且uniq是操作的更大組成部分。這是直觀的,作爲O(n)(最好),而簡單的級聯是O(1)。所以,如果你真的想加快速度,你需要看看<=>運算符是如何爲數組中的對象實現的。我相信大部分時間都在比較對象,以確保最終陣列中任何一對之間的不平等。

+0

那麼管道運營商會利用<=>運營商,如果我只是超載呢?我不確定是否可以加快速度,因爲您可以看到它所比較的​​對象非常簡單,但是如果我只是比較源列而不是所有對象,它可能會加快速度5列..我們將看到。雖然很好的答案! – Rabbott 2010-02-11 19:36:22

+1

教一個人釣魚...很好的答案。 – 2014-12-12 18:21:18

1

使用Array#concat方法可能會快不少,根據我的使用Ruby 1.8的初始基準。 7:

require 'benchmark' 

def reset_arrays! 
    @array1 = [] 
    @array2 = [] 

    [@array1, @array2].each do |array| 
    10000.times { array << ActiveSupport::SecureRandom.hex } 
    end 
end 

reset_arrays! && puts(Benchmark.measure { @array1 | @array2 }) 
# => 0.030000 0.000000 0.030000 ( 0.026677) 

reset_arrays! && puts(Benchmark.measure { @array1.concat(@array2) }) 
# => 0.000000 0.000000 0.000000 ( 0.000122) 
+1

concat用重複做什麼? – Rabbott 2010-02-11 16:02:13

+0

它使它們保持不變,但是你可以在'Array#uniq'之後去掉dups。 – 2010-02-11 16:14:21

+0

好吧,我還需要測試concat vs +以查看哪個更快。 – Rabbott 2010-02-11 16:19:40

1

試試這個,看看這是任何更快

a = [1,2,3,3,2] 
b = [1,2,3,4,3,2,5,7] 
(a+b).uniq 
7

您是否需要在數組內按特定順序排列項目?如果不是,您可能需要檢查使用Set是否會使速度更快。

更新

添加到另一個回答者的代碼:

require "set" 
require "benchmark" 

a1 = []; a2 = [] 
[a1, a2].each do |a| 
    1000000.times { a << rand(999999) } 
end 

s1, s2 = Set.new, Set.new 

[s1, s2].each do |s| 
    1000000.times { s << rand(999999) } 
end 

puts "Merge with pipe:" 
puts Benchmark.measure { a1 | a2 } 

puts "Merge with concat and uniq:" 
puts Benchmark.measure { (a1 + a2).uniq } 

puts "Concat only:" 
puts Benchmark.measure { a1 + a2 } 

puts "Uniq only:" 
b = a1 + a2 
puts Benchmark.measure { b.uniq } 

puts "Using sets" 
puts Benchmark.measure {s1 + s2} 

puts "Starting with arrays, but using sets" 
puts Benchmark.measure {s3, s4 = [a1, a2].map{|a| Set.new(a)} ; (s3 + s4)} 

給出(對於紅寶石1.8.7(2008-08-11 PATCHLEVEL 72)[萬向darwin10.0])

Merge with pipe: 
    1.320000 0.040000 1.360000 ( 1.349563) 
Merge with concat and uniq: 
    1.480000 0.030000 1.510000 ( 1.512295) 
Concat only: 
    0.010000 0.000000 0.010000 ( 0.019812) 
Uniq only: 
    1.460000 0.020000 1.480000 ( 1.486857) 
Using sets 
    0.310000 0.010000 0.320000 ( 0.321982) 
Starting with arrays, but using sets 
    2.340000 0.050000 2.390000 ( 2.384066) 

根據您的情況(大量合併或不多的合併),建議集合可能會更快或者可能不會更快。

+0

順序並不重要,因爲我們必須在所有合併後對數組進行混洗 - 但使用集合合併比使用concat合併慢,這是迄今爲止我們能夠提出的最快方法。我必須使用數組,因爲我正在合併數據庫中的ActiveRecord數據集,這是一個數組..(我認爲) – Rabbott 2010-02-12 14:32:31

+0

如果兩個數組最初都是數據庫實體並且速度是您關心的問題,那麼您可以考慮在數據庫之前合併它們構建對象。在不瞭解模式細節的情況下,無法真正提供一個例子(或者評估我剛纔寫的:-)的可行性),但這可能值得研究。 – chesterbr 2016-06-06 20:12:31

+0

另一件事:你從數據庫中得到的不是一個真正的數組,而是一個「ActiveRecord :: Result」(http://api.rubyonrails.org/classes/ActiveRecord/Result.html)。正如你在這些文檔中看到的那樣,這個類包含了'Enumerable',這就是爲什麼它大部分時間都像一個Array一樣「嘎嘎」(也是爲什麼它很方便 - 而且經常被隱式地稱爲 - 'to_a'來轉換它到一個實際的'陣列')。 – chesterbr 2016-06-06 20:18:40