2012-05-13 15 views
5

के आधार पर संख्याओं की एक सरणी सॉर्ट करें मेरे पास दो सरणी हैं। पहले सरणी में सॉर्ट ऑर्डर होता है। दूसरे सरणी में तत्वों की मनमानी संख्या होती है।दिए गए आदेश

मेरे पास संपत्ति है कि दूसरे सरणी से सभी तत्व (मूल्य-वार) पहले सरणी में होने की गारंटी है, और मैं केवल संख्याओं के साथ काम कर रहा हूं।

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

जब मैं प्रकार A, मैं तत्वों चाहते हैं Order द्वारा निर्दिष्ट क्रम में प्रकट करने के लिए:

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

ध्यान दें कि डुप्लिकेट निष्पक्ष खेल रहे हैं। ए में तत्वों को बदला नहीं जाना चाहिए, केवल पुनः आदेश दिया जाना चाहिए। मैं यह कैसे कर सकता हूँ?

+1

आपको अपने परिवर्तनीय नाम पूंजी अक्षरों से शुरू नहीं करना चाहिए, तब वे स्थिरांक बन जाते हैं। साथ ही, 'ऑर्डर' के अलावा 'ए' में कोई मूल्य नहीं है? –

+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। आपने मुझे 1 9 सेकेंड तक मार दिया, मैंने अपना जवाब हटा दिया :-) –

+2

@ माइकलकोहल आपने एक अच्छा मुद्दा बना दिया कि यदि यह सरणी बड़ी हो सकती है तो दृष्टिकोण पर पुनर्विचार किया जा सकता है, लेकिन यह अधिकांश उद्देश्यों के लिए पर्याप्त तेज़ होना चाहिए – 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' पहले से ही आंतरिक रूप से मैपिंग मानों की एक अस्थायी सरणी उत्पन्न करता है - क्या यह हैश कैश tuples की सरणी से अधिक कुशल है [प्रलेखन में संदर्भित] (http://apidock.com/ruby/Enumerable/sort_by)? – Gareth

+1

@ गैरेथ हां, क्योंकि 'ऐरे # इंडेक्स' का उपयोग करते हुए आकार _m_ की सरणी में _n_ मानों के लिए औसत _n * m/2_ ऑपरेशंस (सबसे खराब केस: _n * m_) की आवश्यकता होती है, जबकि हैश लुकअप का उपयोग करते समय हमेशा _m_ ऑपरेशंस का उपयोग करता है (या उस मामले के लिए _n + m_ जहां आप गणना में हैशिंग समय शामिल कर रहे हैं)। इसके अलावा, 'इंडेक्स 'के लिए _n_ धीमी रूबी भूमि में होना चाहिए, जबकि हैश तैयारी के साथ _n_ लगभग पूरी तरह से सी में होता है। मेरा संपादन देखें। – Phrogz

+0

@ गैरेथ लेकिन, जैसा कि आपने अपनी टिप्पणी में कहा था, आपका उत्तर शायद अधिकांश समय "पर्याप्त तेज़" होगा। उदाहरण के लिए, 10 वस्तुओं में से एक के साथ 50 वस्तुओं की एक सरणी को सॉर्ट करना आपके रास्ते और 15-20μs के माध्यम से लगभग 30μs है। :) – Phrogz

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) 
संबंधित मुद्दे