2012-03-09 8 views
7

Hãy nói rằng tôi có một mảng như thế này:Làm cách nào để tính giá trị trung bình trong các đối tượng nằm trong một mảng?

[ 
    { 
    "player_id"   => 1, 
    "number_of_matches" => 2, 
    "goals"    => 5 
    }, 
    { 
    "player_id"   => 2, 
    "number_of_matches" => 4, 
    "goals"    => 10 
    } 
] 

Tôi muốn có những mục tiêu trung bình mỗi trận đấu giữa tất cả các cầu thủ, không phải là trung bình cho mỗi người chơi cá nhân, nhưng tỷ lệ trung bình toàn diện.

Tôi nhớ rằng hãy thực hiện nó với .each và lưu trữ từng mức trung bình cá nhân và cuối cùng hãy thêm tất cả và chia cho số lượng người chơi tôi có. Tuy nhiên, tôi đang tìm kiếm một cách Ruby/one-liner để làm điều này.

+0

Bạn có thể muốn sửa chữa mảng của bạn/băm để nó thực sự có giá trị Ruby. –

+0

Xin lỗi, tôi nhận được JSON và tôi ánh xạ nó thành một băm. Hãy để tôi chỉnh sửa điều đó. – Nobita

+2

Một lớp lót rất thú vị, nhưng thường bị đánh giá quá mức, IMO. Tôi nghĩ rằng yêu cầu một giải pháp * thanh lịch * và * sạch sẽ tốt hơn so với yêu cầu cho một lớp lót. –

Trả lời

16

Theo yêu cầu, một lớp lót:

avg = xs.map { |x| x["goals"].to_f/x["number_of_matches"] }.reduce(:+)/xs.size 

Một đoạn dễ đọc hơn:

goals, matches = xs.map { |x| [x["goals"], x["number_of_matches"]] }.transpose 
avg = goals.reduce(:+).to_f/matches.reduce(:+) if goals 
+0

Đẹp và sạch sẽ. –

+0

-1 OP yêu cầu một lớp lót. – Kyle

+0

Kyle: Làm điều này trong một dòng sẽ yêu cầu lặp lại mã hoặc kết quả không chính xác. –

0
a = [{player_id:1 , match_num:2, goals: 5}, {player_id:2 , match_num:4, goals: 10}] 

a.reduce(0){|avg, p| avg += p[:goals].to_f/p[:match_num]}/a.size 

Edit: đổi tên phím và args khối để giảm số lượng char. Đối với những người quan tâm.

Trước tiên, các phím của bạn cần sử dụng => nếu bạn định sử dụng chuỗi làm khóa.

reduce sẽ lặp qua mảng và cộng tổng số trung bình cá nhân cho mỗi người chơi và cuối cùng chúng tôi chia kết quả đó cho tổng số người chơi. '0' trong dấu ngoặc đơn là số bắt đầu của bạn cho reduce.

+1

'arr.map {| p | p [: goal] .to_f/p [: number_of_matches]} .reduce (: +)/arr.size' sẽ ngắn hơn một chút (và không tràn div mã). –

+0

Trong số 93 ký tự trong một lớp lót của bạn, chỉ có 3 ký tự là dấu cách và một vài toán tử xung quanh sẽ làm cho nó dễ đọc hơn nhiều. –

+0

Niklas: bạn đang lập bản đồ và sau đó giảm, do đó lặp lại qua mảng hai lần khi chỉ yêu cầu một lần. – Kyle

1

Sửa đổi nhỏ đối với câu trả lời của tokland.

items.map{|e| e.values_at("goals", "number_of_matches")}.transpose.map{|e| e.inject(:+)}.instance_eval{|goals, matches| goals.to_f/matches} 
+0

Heh, mẹo hay với 'instance_eval' :) Tôi không muốn thấy rằng trong mã sản xuất, mặc dù: P –

0

Để thực hiện chuỗi ngắn hơn, cho phép đổi tên "number_of_matches" để "matches"

a = [ 
    {"player_id":1 , "matches":2, "goals": 5}, 
    {"player_id":2 , "matches":4, "goals": 10} 
] 

a.reduce([0,0]){|sum,h|[sum.first+h["goals"],sum.last+h["matches"]]}.reduce{|sum,m|sum.to_f/m} 
#=> 2.5