2011-03-16 11 views
26

पर्ल मूलभूत मूल्यों के बारे में बहुत अच्छा है:क्या मैं रूबी में डिफ़ॉल्ट मानों के साथ एक सरणी बना सकता हूं?

: [email protected]; perl -e '@foo; printf "%d\n", $foo[123]' 
0 
: [email protected]; perl -e '%foo; printf "%d\n", $foo{bar}' 
0 

रूबी कम से कम हैश के लिए, एक ही कर सकते हैं:

>> foo = Hash.new(0) 
=> {} 
>> foo[:bar] 
=> 0 

लेकिन मालूम होता है एक ही सरणियों के लिए काम नहीं करता:

>> foo = Array.new(0) 
=> [] 
>> foo[123] 
=> nil 
>> foo[124] = 0 
=> 0 
>> foo[456] = 0 
=> 0 
>> foo[455,456] 
=> [nil, 0] 

क्या यह सरणी के लिए डिफ़ॉल्ट मान प्रदान करना संभव है, इसलिए जब वे स्वतः विस्तारित होते हैं, तो वे शून्य के बजाय 0 से भरे होते हैं?

बेशक

मैं इस पर काम कर सकते हैं, लेकिन लागत से अभिव्यक्ति के लिए:

>> foo[457,458] = 890, 321 
=> [890, 321] 
>> foo[456] += 789 
NoMethodError: You have a nil object when you didn't expect it! 
You might have expected an instance of Array. 
The error occurred while evaluating nil.+ 
>> foo.inject(0) {|sum, i| sum += (i || 0) } 
=> 1211 
>> foo.inject(:+) 
NoMethodError: You have a nil object when you didn't expect it! 
You might have expected an instance of Array. 
The error occurred while evaluating nil.+ 

अद्यतन 1: मेरे साथियों में से एक ने कहा कि मैं #inject इस मुद्दे को हल करने के लिए #compact उपयोग कर सकते हैं, और #to_i

>> foo.include? nil 
=> true 
>> foo.compact.inject(:+) 
=> 1211 
>> foo[456,457] 
=> [0, 890, 321] 
>> foo[455..457] 
=> [nil, 0, 890] 
>> foo[455..457].map(&:to_i) 
=> [0, 0, 890] 

अद्यतन 2: के लिए Andrew Grimm के लिए धन्यवाद मानक तत्व-एट-सूचकांक इस मुद्दे को हल करने के लिए += मुद्दे का समाधान:

>> foo = [] 
=> [] 
>> def foo.[](i) 
>> fetch(i) {0} 
>> end 
=> nil 
>> foo[4] 
=> 0 
>> foo 
=> [] 
>> foo[4] += 123 
=> 123 
>> foo 
=> [nil, nil, nil, nil, 123] 

अद्यतन 3: इस अजीब एक तिल की तरह लग रहे करने के लिए शुरू कर रहा है!

>> foo 
=> [nil, nil, nil, nil, 123] 
>> foo[-2..-1] 
TypeError: can't convert Range into Integer 

लेकिन हम साथ सौदा कर सकते हैं:

>> def foo.[](index) 
>> if index.is_a? Range 
>>  index.map {|i| self[i] } 
>> else 
?>  fetch(index) { 0 } # default to 0 if no element at index; will not cause auto-extension of array 
>> end 
>> end 
=> nil 
>> foo 
=> [nil, nil, nil, nil, 123] 
>> foo[-2..-1] 
=> [nil, 123] 

मैं अब (स्वीकार) स्वीकार करना होगा कि मैं Array उपवर्ग मेरे कोड को अव्यवस्थित से बचने के लिए होगी:

class MyClass 
    class ArrayWithDefault < Array 
    def [](index) 
     if index.is_a? Range 
     index.map {|i| self[i] } 
     else 
     fetch(index) { 0 } # default to 0 if no element at index; will not cause auto-extension of array 
     end 
    end 
    end 
end 

के लिए धन्यवाद सभी रचनात्मक समाधान। वास्तव में TIMTOWTDI!

+1

यदि आपको स्पैस सरणी की आवश्यकता है, तो पूर्णांक कुंजी के साथ हैश का उपयोग करने में क्या गलत है? – Simon

+0

मुझे आश्चर्य है कि क्या किसी भी PHP डेवलपर्स ने शिकायत की है कि रूबी में उनकी सरणी/हैश डेटा संरचना मौजूद नहीं है। –

+0

साइमन: मैं पहले स्थान पर हैश के साथ गया था, लेकिन कुछ # मैप्स और # इंजेक्ट्स के साथ मुझे दर्द है जो मुझे करने की ज़रूरत है। –

उत्तर

15

यह देखते हुए कि रूबी एक गैर-मौजूद तत्व के लिए रिटर्न nil (के रूप में करने का विरोध किया सूचकांक-आउट-ऑफ-सीमा प्रकार की त्रुटि बंदर पैच दृष्टिकोण

a = [1,2,3] 
puts a[5] # => nil 
puts a[5] || "a default" # => a default 

आप ले सकता है, लेकिन आप शायद एक 1-फ़ाइल स्क्रिप्ट से बड़ा कुछ भी में यह करने के लिए नहीं चाहते हैं:), तो आप सिर्फ एक "या" इस्तेमाल कर सकते हैं

a = [1,2,3] 
def a.[](index) 
    self.at(index) || "a default" 
end 
puts a[5] # => "a default" 
+7

या आप 'a.fetch {"एक डिफ़ॉल्ट"} 'कर सकते हैं। –

+0

एंड्रयू: कमाल! 'def foo। [] (i); fetch (i) {0} end' –

+1

एंड्रयू: भी, मुझे 'def obj.method' वाक्यविन्यास के बारे में पता नहीं था। 'Obj.instance_eval {def method ...}' से बहुत अच्छा है! –

103

नहीं ऑटो बढ़ाया है, लेकिन कोई डिफ़ॉल्ट मान के साथ निर्दिष्ट लंबाई के लिए शुरू:

>> Array.new(123, 0) 
=> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 
+1

यह उदाहरण यह काम नहीं करता है जब यह स्वतः-विस्तारित होगा। – Gareve

+0

क्या इससे अधिक स्मृति बर्बाद नहीं होगी? – Kunok

1

मुझे लगता है कि यदि आप सर को विस्तारित करना चाहते हैं तो एक सरणी गलत सार तत्व है। अमूर्तता का एक और स्तर जोड़ें।

संपादित करें (हमारी चर्चा से): महत्वपूर्ण बात यह कोड प्राप्त करने के लिए है कि अपने लक्ष्य (एकल जिम्मेदारी सिद्धांत) सही जगह में स्थित है, और उस जगह नहीं अपने "क्लाइंट कोड" है, इसलिए एक नई कक्षा की आवश्यकता है।मौजूदा ऐरे वर्ग (विरासत/मिश्रण के माध्यम से) को विस्तारित करना संभवतः एक नई कक्षा में वांछित व्यवहार को समाहित करने से बेहतर है।

+1

यह जानने के बिना कि मैं क्या कर रहा हूं, यह तय करना कि क्या अमूर्त सही है, काफी असंभव लगता है। ऐरे ऑटो-एक्सटेंशन एक रूबी फीचर है, तो मैं एक ही चीज़ को पूरा करने के लिए अमूर्तता की एक और परत क्यों बनाना चाहूंगा क्योंकि डिफ़ॉल्ट ऐरे व्यवहार मुझे देता है? रूबी जावा नहीं है। ;) –

+0

सहमत हुए। मैं जो प्राप्त कर रहा हूं वह यह है कि आप एक वर्ग में विस्तारित व्यवहार को एक ऐसे नाम से जोड़ना चाहते हैं जो आपको बताता है कि यह वर्ग मौजूदा वर्ग पर बंदर पैच व्यवहार की बजाय क्या करता है। यह विरासत/मिश्रण या रूबी के कुछ अन्य तकनीक के माध्यम से पूरा किया जा सकता है। –

+1

आप सही हैं हालांकि मैं एक रूबी गुरु की बजाय कुछ रूबी सीखने वाला सी ++ प्रोग्रामर हूं :) –

2

एक और दृष्टिकोण हैं Array#[] विधि अधिभावी हो सकता है और डिफ़ॉल्ट मान लौट कोई आइटम नहीं है अगर

class Array   
    def [](index) 
    self.at(index) ? self.at(index) : 0 
    end 
end 

और

arr = [1,2,3] 
puts arr[0] # print 1 
puts arr[5] # print 0 
+0

मुझे वास्तव में यह पसंद है, हालांकि ऐरे क्लास बंदर-पैचिंग के बजाय, मैं बस उस विशिष्ट सरणी पर ओवरराइड करूंगा जिसका मैं परवाह करता हूं। –

3

आप पूर्णांकों के साथ काम कर रहे हैं तो आप to_i कॉल कर सकते हैं:

foo = [] 
foo[100] 
#=> nil 
foo[100].to_i 
#=> 0 
foo[100] = 3 
foo[100] 
#=> 3 

युपीडी

ओह, मैं सभी विषय :)

ताकि आप इसका उपयोग कर सकते पढ़ नहीं किया:

foo.inject{|a,b| a.to_i + b.to_i } 

जो, वास्तव में, नहीं सबसे स्मार्ट

+0

धन्यवाद, यह वही था जो मुझे चाहिए था। – snowe

3

मैं हूँ जोहान्स को सुरुचिपूर्ण समाधान दें: foo.compact.inject(:+)

+0

प्रॉक्सी के लिए धन्यवाद! ;) –

संबंधित मुद्दे

 संबंधित मुद्दे