আমি রুবি অ্যারে থেকে কীভাবে গড় তৈরি করব?


209

কিভাবে অ্যারে থেকে গড় পাবেন?

আমার যদি অ্যারে থাকে:

[0,4,8,2,5,0,2,6]

গড় আমাকে 3.375 দেবে।


11
আপনি যদি এই সংখ্যার গড় হিসাবে 21.75 পেয়ে থাকেন তবে কিছু খুব ভুল ...
সেজেজোজ

2
বিন্দু, আপনি কীভাবে २१.75 got পেয়েছেন তা নিশ্চিত নন তবে ডেটা সেটের জন্য গড় / গড় গড় ৩.৩ the৫ এবং যোগফল ২ is। দয়া করে ডাবল চেক করুন এবং নিশ্চিত হন যে গড়টি আপনার পরে কী!
পল স্যাসিক

2
আমি কোথা থেকে 21.75 পেয়েছি আমার কোনও ধারণা নেই। ক্যালকুলেটরে 0 + 48 + 2 + 5 + 0 + 2 + 6 এর মতো কিছু চাপতে হবে!
বিন্দু

16
যেহেতু এটিকে রুবি-অন-রেলও ট্যাগ করা হয়েছে, আপনি যদি একটি অ্যাক্টিভেকর্ড অ্যারে গড় করছেন তবে সক্রিয় রেকর্ড গণনাগুলি মূল্যবান। পার্সোন.ভেরেজ (: বয়স,: দেশ => 'ব্রাজিল') ব্রাজিলের মানুষের গড় বয়স ফিরিয়ে দেয়। বেশ দারুন!
কাইল হিরোনিমাস

উত্তর:


259

এটা চেষ্টা কর:

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খুব সুন্দর তবে সম্ভবত কী চলছে তা আপনি যদি জানেন না তবে কিছুটা চালাকও। :+প্রতীক; যখন ইনজেকশনে পাস করা হয় তখন এটি সংযোজকের মানটির বিপরীতে প্রতিটি উপাদানকে প্রতীক দ্বারা চিহ্নিত পদ্ধতি প্রয়োগ করে (এই ক্ষেত্রে সংযোজন অপারেশন)।


6
আপনি to_f এবং শেষ করতে পারেন? ইনিশিয়াল মান ক্ষণস্থায়ী দ্বারা অপারেটর উদ্বুদ্ধ করতে: arr.inject(0.0) { |sum,el| sum + el } / arr.size
ডেভ রায়

103
বা: অরআরিনজেক্ট (: +)। টু_ফ / আরআর সাইজ # => 3.375
গ্লেন জ্যাকম্যান

5
আমি মনে করি না যে এই ওয়ারেন্টগুলি অ্যারে শ্রেণিতে যুক্ত হচ্ছে, যেহেতু অ্যারেটি থাকতে পারে এমন সমস্ত ধরণের এটি সাধারণীকরণযোগ্য নয়।
সারা মেই

8
@ জন: এটি # টু_প্রোক রূপান্তর ঠিক প্রতীক নয় - এটি injectডকুমেন্টেশনে উল্লিখিত ইন্টারফেসের অংশ । to_procঅপারেটর &
চাক

21
আপনি যদি Array#injectরেলগুলি ব্যবহার করেন তবে এখানে ওভারকিল। শুধু ব্যবহার #sum। উদাহরণস্বরূপarr.sum.to_f / arr.size
নিক

113
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

4
আমি মনে করি না এটি খুব চালাক। আমি মনে করি এটি মূর্খতার সাথে সমস্যার সমাধান করে। অর্থাৎ এটি হ্রাস ব্যবহার করে যা সঠিকভাবে exactly প্রোগ্রামারদের কোনটি সঠিক, তা কেন সঠিক, তা বুঝতে এবং তারপরে প্রচার করতে উত্সাহিত করা উচিত। গড়ের মতো তুচ্ছ অপারেশনের জন্য, সত্য, একজনকে "চালাক" হওয়ার দরকার নেই। তবে "হ্রাস" কোন তুচ্ছ মামলার জন্য তা বোঝার পরে, কেউ এটিকে আরও জটিল সমস্যাগুলিতে প্রয়োগ করা শুরু করতে পারেন। ভোট দিন।
pduey

3
এখানে উদাহরণস্বরূপের প্রয়োজন কেন?
tybro0103

10
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
বেনিয়ামিন মানস

2
আমি জানি না, উদাহরণস্বরূপ এভাবে ব্যবহার করা কেবল অদ্ভুত বলে মনে হয়, এবং এর সাথে অনেকগুলি জড়িত রয়েছে যা এই পদ্ধতির একটি খারাপ ধারণা তৈরি করে, আইএমও। (উদাহরণস্বরূপ, যদি আপনি selfসেই ব্লকের ভিতরে ভেরিয়েবল বা কোনও পদ্ধতি অ্যাক্সেস করার চেষ্টা করেন এবং সমস্যাটি সমাধান করতে চান তবে) রূপান্তর instance_evalবা ডিএসএল এর জন্য আরও বেশি।
আজেদী 32

1
@ আজেদী 32 আমি সম্মত, এটি আপনার আবেদন কোডটিতে ব্যবহার করবেন না। আমার repl এ পেস্ট করতে সক্ষম হওয়ায় এটি খুব ভাল লাগছিল (:
অ্যানিমেটেড

94

আমি বিশ্বাস করি এর সহজ উত্তরটি

list.reduce(:+).to_f / list.size

1
এটি খুঁজে পেতে আমার একটি মুহুর্ত লাগল - reduceএটি Enumerableব্যবহৃত মিক্সিনের একটি পদ্ধতি Array। এবং এর নাম সত্ত্বেও, আমি @ শুভু ... এর সাথে একমত হয়েছি যদি না আপনি যদি প্রয়োগগুলি ব্যবহার করে রেলগুলি ব্যবহার করেন sum
টম হ্যারিসন

আমি এখানে সমাধানগুলি দেখতে পাচ্ছি যে আমি জানি যে এটি অত্যন্ত ঝরঝরে চেহারা, তবে ভবিষ্যতে আমি যদি আমার কোডটি পড়ি তবে তারা ভয়ঙ্কর পছন্দ করবে I'm পরিষ্কার সমাধানের জন্য ধন্যবাদ!
এটিমোসেক্স

আমার সিস্টেমে এটি গৃহীত উত্তরের চেয়ে 3x গতিযুক্ত।
সার্জিও

48

আমি ম্যাথ.এভারেজ (মান) এর জন্য প্রত্যাশী ছিলাম, তবে এরকম কোনও ভাগ্য নেই।

values = [0,4,8,2,5,0,2,6]
average = values.sum / values.size.to_f

3
আমি বুঝতে পারি নি যে # সুমটি রেলগুলি যুক্ত করেছে! যে ইশারা জন্য ধন্যবাদ।
ডেনি আব্রাহাম

11
ক্রিসমাস 2016 (রুবি 2.4) পর এরে হবে একটি আছে sumতাই এই 6 বছর পর একটি সঠিক উত্তর, জ্যোতিষী পুরস্কার যোগ্য উপস্থিত হতে পারে, পদ্ধতি।
স্টেনস্লাগ

38

রুবি সংস্করণ> = 2.4 এর একটি পরিসংখ্যক # যোগ পদ্ধতি রয়েছে।

এবং ভাসমান পয়েন্ট গড় পেতে, আপনি পূর্ণসংখ্যা # এফডিআইভি ব্যবহার করতে পারেন

arr = [0,4,8,2,5,0,2,6]

arr.sum.fdiv(arr.size)
# => 3.375

পুরানো সংস্করণগুলির জন্য:

arr.reduce(:+).fdiv(arr.size)
# => 3.375

9

শীর্ষ সমাধানগুলির কয়েকটি মানদণ্ড (সবচেয়ে দক্ষতার সাথে):

বড় অ্যারে:

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)

আপনার মানদণ্ডটি কিছুটা ভুল। এই ধরণের তুলনা করার জন্য বেঞ্চমার্ক / আইপিএস আসলে ভাল। আরও বাস্তবসম্মত ফলাফল পেতে আমি নেতিবাচক এবং ধনাত্মক সংখ্যার পাশাপাশি ভাসমান সংখ্যার সাথে এলোমেলোভাবে একটি জন অ্যারে ব্যবহার করার পরামর্শ দেব। আপনি দেখতে পাবেন যে দৃষ্টান্ত_ভেন্য অ্যারে.সুম.ফডিভের চেয়ে ধীর। ভাসমানগুলির জন্য প্রায় 8x দ্বারা। এবং পূর্ণসংখ্যার জন্য প্রায় x1.12। এছাড়াও, বিভিন্ন ওএস বিভিন্ন ফলাফল দেবে। আমার ম্যাকের উপর এই কয়েকটি পদ্ধতি আমার লিনাক্স
ড্রপল্টের

এছাড়াও যোগ পদ্ধতিটি সমষ্টি গণনা করার পরিবর্তে বিভিন্ন পরিসরে গাউসের সূত্র ব্যবহার করে।
সনথোষ

4
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

2
পূর্ণসংখ্যা বিভাগের কারণে এটি ভুল মানগুলি প্রদান করে। উদাহরণস্বরূপ, [2,3] .মানের সাথে এটি ব্যবহার করে দেখুন, যা 2.5 এর পরিবর্তে 2 ফেরৎ দেয়।
জন ফেমেনিলা

1
খালি অ্যারেতে nil0 এর চেয়ে যোগফল কেন হওয়া উচিত ?
অ্যান্ড্রু গ্রিম

1
কারণ আপনি [] এবং [0] এর মধ্যে পার্থক্য পেতে পারেন। এবং আমি মনে করি যে প্রত্যেকে সত্যিকারের অর্থ চান তারা টো_আই ব্যবহার করতে পারেন বা উপরের
শূন্যটি

4

আমাকে এমন কিছু প্রতিযোগিতায় নিয়ে আসি যা বিভাগকে শূন্য সমস্যার সমাধান করে:

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

বিটিডাব্লু: আমি মনে করি এটি সঠিক যে খালি তালিকার গড় শূন্য। কোনও কিছুর গড়পড়তা কিছু নয়, 0 নয় So তবে, আপনি যদি এতে পরিবর্তন করেন:

class Array;def avg;reduce(0.0,:+).try(:/,size);end;end

খালি অ্যারেগুলির ফলাফলটি আমার প্রত্যাশার মতো ব্যতিক্রম হবে না তবে পরিবর্তে এটি এনএএন ফেরায় ... আমি রুবিতে এর আগে কখনও দেখিনি। ;-) মনে হচ্ছে ভাসা শ্রেণীর একটি বিশেষ আচরণ ...

0.0/0 #==> NaN
0.1/0 #==> Infinity
0.0.class #==> Float

4

আমি গৃহীত সমাধান সম্পর্কে কি পছন্দ করি না

arr = [5, 6, 7, 8]
arr.inject{ |sum, el| sum + el }.to_f / arr.size
=> 6.5

এটি আসলে খাঁটি কার্যকরী উপায়ে কাজ করে না। শেষে arr.size গণনা করতে আমাদের একটি পরিবর্তনশীল আর্টের প্রয়োজন need

খাঁটি কার্যকরভাবে এটি সমাধান করার জন্য আমাদের দুটি মানের ট্র্যাক রাখতে হবে: সমস্ত উপাদানগুলির যোগফল এবং উপাদানের সংখ্যা।

[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(:/)
সন্তোষ

@ সন্তোষ: হ্যাঁ, এটি অনেক বেশি পাঠযোগ্য! যদিও আমি এটিকে "ছত্রভঙ্গ" বলব না, আমি এটিকে "ধ্বংসাত্মক" বলব
টনি.পিটলুগা

3

পাবলিক বিনোদন, আরও একটি সমাধান:

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

1
ভোটিংয়ে এটি যদি বেশি হয় তবে আমি বুঝতে পারতাম না! খুব ভালো.
ম্যাট স্টিভেনস

সাফ চতুরের চেয়ে ভাল , কোডের এই অংশটি পরিষ্কার নয়।
সেবাস্তিয়ান পালমা

2

এই পিসিতে রুবি করবেন না, তবে এই মাত্রায় কিছু কাজ করা উচিত:

values = [0,4,8,2,5,0,2,6]
total = 0.0
values.each do |val|
 total += val
end

average = total/values.size

2

অ্যাড Array#average

আমি প্রায়শই একই জিনিসটি করছিলাম তাই আমি ভেবেছিলাম কেবল Arrayএকটি সাধারণ averageপদ্ধতিতে ক্লাসটি প্রসারিত করা বুদ্ধিমান । এটি পূর্ণসংখ্যার বা ভাসমান বা দশমিকের মতো সংখ্যার অ্যারের ছাড়াও কোনও কিছুর জন্য কাজ করে না তবে আপনি যখন এটি সঠিকভাবে ব্যবহার করেন তখন তা কার্যকর।

আমি রুবেলগুলিকে রেলগুলি ব্যবহার করছি তাই এটি আমি রেখেছি config/initializers/array.rbতবে আপনি এটি বুট ইত্যাদিতে যে কোনও জায়গায় রেখে দিতে পারেন can

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

1
a = [0,4,8,2,5,0,2,6]
sum = 0
a.each { |b| sum += b }
average = sum / a.length

4
পূর্ণসংখ্যা বিভাগের কারণে এটি ভুল মানগুলি ফিরিয়ে দেবে। উদাহরণস্বরূপ, যদি একটি [2, 3] হল, প্রত্যাশিত ফলাফলের 2.5, কিন্তু আপনি 2. ফিরে আসবেন
জন Feminella

1
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


1

এই পদ্ধতিটি সহায়ক হতে পারে।

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
ওভারফ্লো এখানে স্ট্যাক করতে স্বাগতম স্বাগতম প্রশ্নের মূল পোস্টারটি উত্তরটি 3.375 হিসাবে চায় এবং আপনার সমাধানটি দেয় 3. i, e
27/8

আপনার মন্তব্যের জন্য আপনাকে ধন্যবাদ। আমি জানি প্রশ্নের মূল পোস্টারটি 3.375 হিসাবে উত্তর চায় এবং আমি ভ্যারিয়েবলকে 'ভ' ভাসমান ভ্যালু (যেমন; 0.0) দিয়েছি বলে এই পদ্ধতিটি কী করে তা আমি জানি। মুনিম মুন্না আপনার সাথে আমার একমত হতে হবে সেখানে সত্যই অনুরূপ উত্তর আছে।
কিশোর বুধাথোকি

0

অ্যারের পুনরাবৃত্তি না করে (উদাহরণস্বরূপ এক-লাইনারের জন্য উপযুক্ত):

[1, 2, 3, 4].then { |a| a.sum.to_f / a.size }


-1

আপনি নিম্নলিখিত মত কিছু চেষ্টা করতে পারেন:

a = [1,2,3,4,5]
# => [1, 2, 3, 4, 5]
(a.sum/a.length).to_f
# => 3.0
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.