किसी ऐरे से औसत कैसे मिलेगा?
अगर मेरे पास सरणी है:
[0,4,8,2,5,0,2,6]
एवरेजिंग मुझे 3.375 देगा।
किसी ऐरे से औसत कैसे मिलेगा?
अगर मेरे पास सरणी है:
[0,4,8,2,5,0,2,6]
एवरेजिंग मुझे 3.375 देगा।
जवाबों:
इसे इस्तेमाल करे:
arr = [5, 6, 7, 8]
arr.inject{ |sum, el| sum + el }.to_f / arr.size
=> 6.5
ध्यान दें .to_f
, जो आप पूर्णांक विभाजन से किसी भी समस्या से बचने के लिए चाहते हैं। आप भी कर सकते हैं:
arr = [5, 6, 7, 8]
arr.inject(0.0) { |sum, el| sum + el } / arr.size
=> 6.5
आप इसे Array
एक और टिप्पणीकार के सुझाव के रूप में परिभाषित कर सकते हैं , लेकिन आपको पूर्णांक विभाजन से बचने की आवश्यकता है या आपके परिणाम गलत होंगे। इसके अलावा, यह आम तौर पर हर संभव तत्व प्रकार पर लागू नहीं होता है (जाहिर है, एक औसत केवल उन चीजों के लिए समझ में आता है जो औसतन हो सकते हैं)। लेकिन अगर आप उस मार्ग पर जाना चाहते हैं, तो इसका उपयोग करें:
class Array
def sum
inject(0.0) { |result, el| result + el }
end
def mean
sum / size
end
end
यदि आपने पहले नहीं देखा है inject
, तो यह उतना जादुई नहीं है जितना यह दिखाई दे सकता है। यह प्रत्येक तत्व पर पुनरावृत्ति करता है और फिर उस पर एक संचायक मान लागू करता है। फिर संचायक को अगले तत्व को सौंप दिया जाता है। इस मामले में, हमारा संचायक केवल एक पूर्णांक है जो पिछले सभी तत्वों के योग को दर्शाता है।
संपादित करें: टिप्पणीकार डेव रे ने एक अच्छा सुधार प्रस्तावित किया।
संपादित करें: टिप्पणीकार ग्लेन जैकमैन का प्रस्ताव, उपयोग करना arr.inject(:+).to_f
, बहुत अच्छा है, लेकिन शायद थोड़ा बहुत चालाक है अगर आपको नहीं पता कि क्या चल रहा है। :+
प्रतीक है; जब इसे इंजेक्ट किया जाता है, तो यह संचयकर्ता मूल्य के विरुद्ध प्रत्येक तत्व को प्रतीक द्वारा नामित विधि (इस मामले में, अतिरिक्त संचालन) को लागू करता है।
arr.inject(0.0) { |sum,el| sum + el } / arr.size
:।
inject
इंटरफ़ेस का हिस्सा है , जिसका प्रलेखन में उल्लेख किया गया है। to_proc
ऑपरेटर है &
।
Array#inject
तो यहां ओवरकिल है। बस उपयोग करें #sum
। उदाarr.sum.to_f / arr.size
a = [0,4,8,2,5,0,2,6]
a.instance_eval { reduce(:+) / size.to_f } #=> 3.375
इसका एक संस्करण जो उपयोग नहीं करता है वह instance_eval
होगा:
a = [0,4,8,2,5,0,2,6]
a.reduce(:+) / a.size.to_f #=> 3.375
instance_eval
आपको केवल a
एक बार निर्दिष्ट करते हुए कोड चलाने देता है , इसलिए इसे अन्य आदेशों के साथ जंजीर बनाया जा सकता है। यानी random_average = Array.new(10) { rand(10) }.instance_eval { reduce(:+) / size.to_f }
बजायrandom = Array.new(10) { rand(10) }; random_average = random.reduce(:+) / random.size
self
उस ब्लॉक के अंदर चर या विधि का उपयोग करने का प्रयास किया है, तो आप समस्याओं में भाग लेंगे।) instance_eval
मेटाप्रोग्रामिंग या डीएसएल के लिए अधिक है।
मेरा मानना है कि सबसे सरल उत्तर है
list.reduce(:+).to_f / list.size
reduce
की एक विधि है जिसका Enumerable
उपयोग किया जाता है Array
। और इसके नाम के बावजूद, मैं @ShuWu से सहमत हूं ... जब तक आप रेल का उपयोग नहीं कर रहे हैं जो लागू करता है sum
।
मैं Math.aiture (मूल्यों) के लिए उम्मीद कर रहा था, लेकिन ऐसी कोई किस्मत नहीं।
values = [0,4,8,2,5,0,2,6]
average = values.sum / values.size.to_f
sum
, इसलिए यह 6 साल बाद एक सही उत्तर प्रतीत होता है, नास्त्रेदमस पुरस्कार के योग्य।
रूबी संस्करण> = 2.4 में एक एन्युमरेबल # योग है पद्धति है।
और फ्लोटिंग पॉइंट एवरेज पाने के लिए, आप Integer # fdiv का उपयोग कर सकते हैं
arr = [0,4,8,2,5,0,2,6]
arr.sum.fdiv(arr.size)
# => 3.375
पुराने संस्करणों के लिए:
arr.reduce(:+).fdiv(arr.size)
# => 3.375
शीर्ष समाधान के कुछ बेंचमार्किंग (सबसे कुशल के क्रम में):
array = (1..10_000_000).to_a
Benchmark.bm do |bm|
bm.report { array.instance_eval { reduce(:+) / size.to_f } }
bm.report { array.sum.fdiv(array.size) }
bm.report { array.sum / array.size.to_f }
bm.report { array.reduce(:+).to_f / array.size }
bm.report { array.reduce(:+).try(:to_f).try(:/, array.size) }
bm.report { array.inject(0.0) { |sum, el| sum + el }.to_f / array.size }
bm.report { array.reduce([ 0.0, 0 ]) { |(s, c), e| [ s + e, c + 1 ] }.reduce(:/) }
end
user system total real
0.480000 0.000000 0.480000 (0.473920)
0.500000 0.000000 0.500000 (0.502158)
0.500000 0.000000 0.500000 (0.508075)
0.510000 0.000000 0.510000 (0.512600)
0.520000 0.000000 0.520000 (0.516096)
0.760000 0.000000 0.760000 (0.767743)
1.530000 0.000000 1.530000 (1.534404)
array = Array.new(10) { rand(0.5..2.0) }
Benchmark.bm do |bm|
bm.report { 1_000_000.times { array.reduce(:+).to_f / array.size } }
bm.report { 1_000_000.times { array.sum / array.size.to_f } }
bm.report { 1_000_000.times { array.sum.fdiv(array.size) } }
bm.report { 1_000_000.times { array.inject(0.0) { |sum, el| sum + el }.to_f / array.size } }
bm.report { 1_000_000.times { array.instance_eval { reduce(:+) / size.to_f } } }
bm.report { 1_000_000.times { array.reduce(:+).try(:to_f).try(:/, array.size) } }
bm.report { 1_000_000.times { array.reduce([ 0.0, 0 ]) { |(s, c), e| [ s + e, c + 1 ] }.reduce(:/) } }
end
user system total real
0.760000 0.000000 0.760000 (0.760353)
0.870000 0.000000 0.870000 (0.876087)
0.900000 0.000000 0.900000 (0.901102)
0.920000 0.000000 0.920000 (0.920888)
0.950000 0.000000 0.950000 (0.952842)
1.690000 0.000000 1.690000 (1.694117)
1.840000 0.010000 1.850000 (1.845623)
class Array
def sum
inject( nil ) { |sum,x| sum ? sum+x : x }
end
def mean
sum.to_f / size.to_f
end
end
[0,4,8,2,5,0,2,6].mean
nil
0 के बजाय एक योग क्यों होना चाहिए ?
मुझे प्रतियोगिता में कुछ लाने दो जो शून्य समस्या द्वारा विभाजन को हल करता है:
a = [1,2,3,4,5,6,7,8]
a.reduce(:+).try(:to_f).try(:/,a.size) #==> 4.5
a = []
a.reduce(:+).try(:to_f).try(:/,a.size) #==> nil
हालाँकि, मुझे स्वीकार करना चाहिए कि "कोशिश" एक रेल सहायक है। लेकिन आप इसे आसानी से हल कर सकते हैं:
class Object;def try(*options);self&&send(*options);end;end
class Array;def avg;reduce(:+).try(:to_f).try(:/,size);end;end
BTW: मुझे लगता है कि यह सही है कि एक खाली सूची का औसत शून्य है। कुछ नहीं का औसत कुछ भी नहीं है, 0. इसलिए यह अपेक्षित व्यवहार नहीं है। हालाँकि, यदि आप इसमें परिवर्तन करते हैं:
class Array;def avg;reduce(0.0,:+).try(:/,size);end;end
खाली एरे के लिए परिणाम एक अपवाद नहीं होगा जैसा कि मैंने उम्मीद की थी, लेकिन इसके बजाय NaN देता है ... मैंने रूबी में पहले कभी नहीं देखा है। ;; को फ्लोट वर्ग का एक विशेष व्यवहार लगता है ...
0.0/0 #==> NaN
0.1/0 #==> Infinity
0.0.class #==> Float
मुझे स्वीकृत समाधान के बारे में क्या पसंद नहीं है
arr = [5, 6, 7, 8]
arr.inject{ |sum, el| sum + el }.to_f / arr.size
=> 6.5
यह है कि यह वास्तव में शुद्ध रूप से काम नहीं करता है। हमें अंत में arr.size की गणना करने के लिए एक चर गिरफ्तारी की आवश्यकता है।
इस विशुद्ध रूप से कार्यात्मक रूप से हल करने के लिए हमें दो मूल्यों पर नज़र रखने की आवश्यकता है: सभी तत्वों का योग, और तत्वों की संख्या।
[5, 6, 7, 8].inject([0.0,0]) do |r,ele|
[ r[0]+ele, r[1]+1 ]
end.inject(:/)
=> 6.5
संतोष ने इस समाधान में सुधार किया: तर्क आर के बजाय एक सरणी होने के कारण, हम विनाशकारी उपयोग कर सकते हैं इसे तुरंत दो चर के अलावा लेने के लिए
[5, 6, 7, 8].inject([0.0,0]) do |(sum, size), ele|
[ sum + ele, size + 1 ]
end.inject(:/)
यदि आप यह देखना चाहते हैं कि यह कैसे काम करता है, कुछ पुट जोड़ें:
[5, 6, 7, 8].inject([0.0,0]) do |(sum, size), ele|
r2 = [ sum + ele, size + 1 ]
puts "adding #{ele} gives #{r2}"
r2
end.inject(:/)
adding 5 gives [5.0, 1]
adding 6 gives [11.0, 2]
adding 7 gives [18.0, 3]
adding 8 gives [26.0, 4]
=> 6.5
हम राशि और गणना को समाहित करने के लिए एक सरणी के बजाय एक संरचना का उपयोग कर सकते हैं, लेकिन फिर हमें पहले संरचना को घोषित करना होगा:
R=Struct.new(:sum, :count)
[5, 6, 7, 8].inject( R.new(0.0, 0) ) do |r,ele|
r.sum += ele
r.count += 1
r
end.inject(:/)
end.method
रूबी में इस्तेमाल किया गया था, इसके लिए धन्यवाद!
arr.inject([0.0,0]) { |(sum, size), el| [ sum + el, size + 1 ] }.inject(:/)
सार्वजनिक मनोरंजन के लिए, फिर भी एक और समाधान:
a = 0, 4, 8, 2, 5, 0, 2, 6
a.reduce [ 0.0, 0 ] do |(s, c), e| [ s + e, c + 1 ] end.reduce :/
#=> 3.375
Array#average
।मैं एक ही काम काफी बार कर रहा था इसलिए मुझे लगा कि Array
एक साधारण के साथ सिर्फ कक्षा का विस्तार करना समझदारी हैaverage
विधि के । यह किसी भी संख्या के अलावा काम नहीं करता है जैसे कि इंटेगर या फ्लोट्स या दशमलव जैसी संख्या लेकिन जब आप इसे सही उपयोग करते हैं तो यह आसान है।
मैं रूबी ऑन रेल्स का उपयोग कर रहा हूं इसलिए मैंने इसे रखा है config/initializers/array.rb
लेकिन आप इसे कहीं भी रख सकते हैं जो बूट पर शामिल है, आदि।
config/initializers/array.rb
class Array
# Will only work for an Array of numbers like Integers, Floats or Decimals.
#
# Throws various errors when trying to call it on an Array of other types, like Strings.
# Returns nil for an empty Array.
#
def average
return nil if self.empty?
self.sum / self.size
end
end
a = [0,4,8,2,5,0,2,6]
sum = 0
a.each { |b| sum += b }
average = sum / a.length
a = [0,4,8,2,5,0,2,6]
a.empty? ? nil : a.reduce(:+)/a.size.to_f
=> 3.375
एकल शून्य, पूर्णांक विभाजन से विभाजित होता है और पढ़ने में आसान होता है। यदि आप खाली सरणी रिटर्न 0 चुनते हैं तो आसानी से संशोधित किया जा सकता है।
मुझे यह वैरिएंट भी पसंद है, लेकिन यह थोड़ा और चिंताजनक है।
a = [0,4,8,2,5,0,2,6]
a.empty? ? nil : [a.reduce(:+), a.size.to_f].reduce(:/)
=> 3.375
arr = [0,4,8,2,5,0,2,6]
average = arr.inject(&:+).to_f / arr.size
# => 3.375
यह तरीका मददगार हो सकता है।
def avg(arr)
val = 0.0
arr.each do |n|
val += n
end
len = arr.length
val / len
end
p avg([0,4,8,2,5,0,2,6])
[1,2].tap { |a| @asize = a.size }.inject(:+).to_f/@asize
लघु लेकिन उदाहरण चर का उपयोग कर
a_size = nil; [1,2].tap { |a| a_size = a.size }.inject(:+).to_f/a_size
एक उदाहरण चर बनाने के बजाय करूँगा ।
आप निम्नलिखित की तरह कुछ कोशिश कर सकते हैं:
a = [1,2,3,4,5]
# => [1, 2, 3, 4, 5]
(a.sum/a.length).to_f
# => 3.0