2012-05-13 11 views
5

私は2つの配列を持っています。最初の配列にはソート順が含まれています。 2番目の配列には、任意の数の要素が含まれます。与えられた順序に基づいて数字の配列を並べ替える

私は、2番目の配列のすべての要素(値)が最初の配列にあることが保証されており、数値のみを扱っているという性質があります。

A = [1,3,4,4,4,5,2,1,1,1,3,3] 
Order = [3,1,2,4,5] 

ときIソートA、私はOrderで指定された順序で表示されるように要素をしたいと思います:

[3, 3, 3, 1, 1, 1, 1, 2, 4, 4, 4, 5] 

注重複が公正なゲームであることを。 Aの要素は変更しないでください。順序を変更するだけです。これどうやってするの?

+1

変数名は大文字で始めるべきではありません。また、 'Order'以外の' A'には値がありませんか? –

+0

この特定の場合、はい、他の値はありません。いくつかの配列がもともと他の値を持っていた場合、この並べ替えに来る前にフィルタリングされます。 – MxyL

答えて

11
>> source = [1,3,4,4,4,5,2,1,1,1,3,3] 
=> [1, 3, 4, 4, 4, 5, 2, 1, 1, 1, 3, 3] 
>> target = [3,1,2,4,5] 
=> [3, 1, 2, 4, 5] 
>> source.sort_by { |i| target.index(i) } 
=> [3, 3, 3, 1, 1, 1, 1, 2, 4, 4, 4, 5] 
+0

+1。あなたは私にそれを19秒で打つ、私は私の答えを削除しました:-) –

+2

@MichaelKohlこの配列が大きくなる可能性が高い場合、アプローチはおそらく再考される可能性がありますが、これはほとんどの目的には十分速いはずです – Gareth

4

もしガレスの答えではなく、一緒に行く、遅すぎることが判明@(および場合のみ!):

# Pre-create a hash mapping value to index once only… 
index = Hash[ Order.map.with_index.to_a ] #=> {3=>0,1=>1,2=>2,4=>3,5=>4} 

# …and then sort using this constant-lookup-time 
sorted = A.sort_by{ |o| index[o] } 

Benchmarkedに:

require 'benchmark' 

order = (1..50).to_a.shuffle 
items = 1000.times.map{ order.sample } 
index = Hash[ order.map.with_index.to_a ] 

Benchmark.bmbm do |x| 
    N = 10_000 
    x.report("Array#index"){ N.times{ 
    items.sort_by{ |n| order.index(n) } 
    }} 
    x.report("Premade Hash"){ N.times{ 
    items.sort_by{ |n| index[n] } 
    }} 
    x.report("Hash on Demand"){ N.times{ 
    index = Hash[ order.map.with_index.to_a ] 
    items.sort_by{ |n| index[n] } 
    }} 
end 

#=>      user  system  total  real 
#=> Array#index  12.690000 0.010000 12.700000 (12.704664) 
#=> Premade Hash  4.140000 0.000000 4.140000 ( 4.141629) 
#=> Hash on Demand 4.320000 0.000000 4.320000 ( 4.323060) 
+0

'#sort_by'は既に内部的にマッピング値の一時的な配列を生成しています - このハッシュキャッシュはタプルの配列より効率的です(http://apidock.com/ruby/Enumerable/sort_by)? – Gareth

+1

@Garethはい、Array _ indexを使用する_m_配列の_n_値は平均_n * m/2_演算(最悪の場合は_n * m_)を必要とするため、ハッシュルックアップでは常に_m_演算のみを使用します計算にハッシュ時間を含める場合は_n + m_)。さらに、 'index'のための_n_はRubyの遅い土地で行われなければなりませんが、_n_はハッシュの準備がほぼ完全にCで行われます。 – Phrogz

+0

@ガースしかし、あなたのコメントで言ったように、あなたの答えはたぶん "十分に速い"でしょう。たとえば、10個の値のうちの1つを持つ50個のアイテムの配列を並べ替えるのは、あなたの道を使って約30μs、私のやり方を15-20μsです。 :)もちろん、ああ、 – Phrogz

1

もう1つの可能な解決策明示的ソートなし:

source = [1,3,4,4,4,5,2,1,1,1,3,3] 
target = [3,1,2,4,5] 
source.group_by(&lambda{ |x| x }).values_at(*target).flatten(1) 
関連する問題