2011-03-01 10 views
51
(1..4).collect do |x| 
    next if x == 3 
    x + 1 
end # => [2, 3, nil, 5] 
    # desired => [2, 3, 5] 

तो next के लिए स्थिति उत्पन्न होने पर एकत्रित करते हैं, collect सरणी में nil डालता है, जबकि मैं क्या करने की कोशिश कर रहा हूँ लौटे सरणी में कोई तत्व डाल दिया जाता है, तो शर्त है मिला। क्या यह लौटा सरणी पर delete_if { |x| x == nil } पर कॉल किए बिना संभव है?से अधिक जाएं Enumerable # में यात्रा

(रूबी 1.8.7 का उपयोग करना; मेरी कोड अंश भारी पृथक है)

उत्तर

74

विधि Enumerable#reject जो सिर्फ उद्देश्य में कार्य करता है:

(1..4).reject{|x| x == 3}.collect{|x| x + 1} 

सीधे किसी अन्य के एक इनपुट के रूप में एक विधि का उत्पादन का प्रचलन विधि चेनिंग कहा जाता है और बहुत है रुबी में आम है।

बीटीडब्ल्यू, map (या collect) आउटपुट के लिए गणना के इनपुट के प्रत्यक्ष मैपिंग के लिए उपयोग किया जाता है। यदि आपको विभिन्न तत्वों को आउटपुट करने की आवश्यकता है, तो संभावना है कि आपको Enumerable की दूसरी विधि की आवश्यकता है।

संपादित करें: आप तथ्य यह है कि तत्वों में से कुछ दो बार दोहराया जाता है से परेशान हैं, तो आप कम सुरुचिपूर्ण समाधान के आधार पर उपयोग कर सकते हैं inject (या उसके समान विधि each_with_object नाम):

(1..4).each_with_object([]){|x,a| a << x + 1 unless x == 3} 
+3

सुंदर कोड। यह मेरी तुलना में एक बेहतर समाधान है। – Benson

+3

यह सबसे धीमा उत्तर है (हालांकि बहुत अधिक नहीं), लेकिन निश्चित रूप से सबसे साफ है। मेरी इच्छा है कि 'संग्रह' के साथ ऐसा करने का कोई तरीका था, क्योंकि मुझे उम्मीद है कि 'अगली' को "कुछ भी नहीं" (उर्फ 'शून्य ') के बजाय' बिल्कुल 'कुछ नहीं लौटाएगा। –

+1

यदि यह किसी अन्य दृष्टिकोण से धीमा है, तो रूबी का ऑप्टिमाइज़र कुछ कामों का उपयोग कर सकता है जो आपको नहीं लगता? – Shannon

44

मैं बस उसके एवज में सरणी है, जो एक सरणी में नहीं के बराबर से किसी उदाहरण को हटा पर .compact कहेंगे। आप इसे चाहते हैं, तो मौजूदा सरणी (बिना किसी कारण के लिए नहीं) को संशोधित करने, .compact! का उपयोग करें:

(1..4).collect do |x| 
    next if x == 3 
    x 
end.compact! 
+13

मैं एक त्वरित बेंचमार्क किया था, रुचि के लिए, चार समाधान के अब तक का सुझाव दिया: इकट्ठा + कॉम्पैक्ट, इकट्ठा + कॉम्पैक्ट !, + इकट्ठा अस्वीकार और वाई के रूप में परिणाम सरणी का निर्माण कहां जाओ एमआरआई 1.9.1 में, कम से कम, इकट्ठा + कॉम्पैक्ट! एक संकीर्ण मार्जिन द्वारा स्पीड विजेता है, इकट्ठा + कॉम्पैक्ट और अस्वीकार + बहुत करीब पीछे इकट्ठा करें। परिणाम सरणी बनाना लगभग उतना धीमा है जितना धीमा है। –

+0

@glenn: क्या आप अपने बेंचमार्क के लिए निम्नलिखित शामिल करेंगे: '(1..4) .inject ([]) {| a, x | एक्स == 3? ए: a.push (x + 1)} '? धन्यवाद। –

+0

निश्चित रूप से। यह अभी तक सबसे धीमा है, यद्यपि परिणाम सरणी बनाने से थोड़ा धीमा है। मैंने इस तरह के संस्करण को भी जोड़ा है: 'a.inject ([]) {| aa, x | aa << x + 1 जब तक x == 3; aa} ', जो सरणी बनाने से तेज़ था, लेकिन अभी भी तीन 3 तेज तरीकों से काफी धीमी है। –

0

मैं उपयोग करने के लिए सुझाव है:

(1..4).to_a.delete_if {|x| x == 3} 
कलेक्ट + अगले स्टेटमेंट के बजाय

+0

_real_ कोड मेरे प्रश्न में सारणित कोड से अधिक जटिल है, इसलिए दुर्भाग्यवश, जो मैं खोज रहा हूं, वह हासिल नहीं करेगा। (संग्रह वास्तव में इसे वापस करने के बजाय मूल्य को कुशलतापूर्वक उपयोग करता है) –

+0

ठीक है, तो सुझाए गए कॉम्पैक्ट! समाधान आपके लिए एक है। – ALoR

4

सिर्फ एक सुझाव है, तुम क्यों यह इस तरह से नहीं करते हैं: क्या आप सरणी से तत्व नहीं के बराबर दूर करने के लिए एक और यात्रा को बचाया है कि रास्ते में

result = [] 
(1..4).each do |x| 
    next if x == 3 
    result << x 
end 
result # => [1, 2, 4] 

। आशा है कि यह मदद करता है =)

+0

यह मैलाडन के 'अस्वीकार' उदाहरण के एक बहुत अधिक वर्बोज़ संस्करण की तरह है। – Benson

+0

वास्तव में नाप, "अस्वीकार" एक बार सरणी के माध्यम से पुनरावृत्ति करता है, और एक बार फिर से सरणी के माध्यम से "संग्रह" पुनरावृत्त करता है, इसलिए दो पुनरावृत्तियों हैं। "प्रत्येक" के मामले में यह केवल एक बार होता है =) – Staelen

+4

यह एक उचित विचार है, लेकिन रूबी में अक्सर गति परीक्षण करना बहुत दिलचस्प होता है और वास्तव में क्या होता है देखें। मेरे त्वरित बेंचमार्क में (जो निश्चित रूप से एंड्रयू के असली मामले से मेल नहीं खा सकता है), सरणी का निर्माण इस तरह से वास्तव में लगभग किसी भी तरीके से धीमा है। मुझे संदेह है कि मुद्दा यह है कि सी में सरणी के माध्यम से पुनरावृत्ति वास्तव में रूबी << स्तर पर वस्तुओं को जोड़ने से बहुत तेज है। –

0

आप खींच सकता है एक सहायक विधि में निर्णय लेने की, और इसका इस्तेमाल Enumerable#reduce के माध्यम से:

def potentially_keep(list, i) 
    if i === 3 
    list 
    else 
    list.push i 
    end 
end 
# => :potentially_keep 

(1..4).reduce([]) { |memo, i| potentially_keep(memo, i) } 
# => [1, 2, 4] 
संबंधित मुद्दे