2014-11-25 4 views
1

У меня есть массив массивов, подобных этим:получить средние значения из массива массивов

[["Timmy", "90", "47", "89"], ["Simon", "89", "57", "99"]] (etc) 

Мне нужно пройти через каждый подмассива и в общей сложности до числа в каждом и в среднем каждый подрешетки.

Я не уверен, как я буду обращаться к каждому номеру. Любая помощь будет оценена!

+0

Среднее значение чисел в каждой подрешетке, или в среднем по всем подмассивам? – Linuxios

+0

Среднее число в каждом подмассиве. Сожалею! – Destiny

+1

Почему это звучит как домашнее задание? –

ответ

6

Вот возможное решение:

arr = [["Timmy", "90", "47", "89"], ["Simon", "89", "57", "99"]] 
averages = arr.map do |name, *nums| 
    [name, nums.map(&:to_f).inject(:+)/nums.length] 
end 
# => [["Timmy", 75.33333333333333], ["Simon", 81.66666666666667]] 

Это решение использует рубина список понимание, поэтому для каждого элемента в arr выполняется на блоке с параметрами |name, *nums|, name устанавливается на первый элемент массива, и nums устанавливается в остальную часть массива (минус name).

nums.map(&:to_f).inject(:+) превращает каждую строку в число с плавающей запятой, которое затем делится на количество элементов в nums для создания среднего значения.

+0

Трудно улучшить это, кроме возможности добавить '.round (2)' :-). Если вы не знали, где бедный Тимми находится в массиве, вы можете просто изменить '[name, * nums |' to | * nums | '. Ах, да, и, как вы говорите, переходите к 'nums.lenght-1'. –

+1

@CarySwoveland - если вы не знали, где имя, но вы знали там _was_ имя (где-то) в массиве, вы могли бы сделать что-то вроде 'nums.map (&: to_f) .inject (: +)/(число.length - 1) ', так как' 'Timmy" .to_f' будет оценен до '0.0' ... –

+0

После выполнения put из arr после этого блока, я все еще получаю исходный массив. Есть предположения? – Destiny

0

Немного отличается и немного более быстрый вариант:

arr = [["Timmy", "90", "47", "89"], ["Simon", "89", "57", "99"]] 
averages = arr.map do |name, *nums| 
    [name, nums.inject(0){|acc, el| acc + el.to_f}/nums.length] 
end 
p averages 
# => [["Timmy", 75.33333333333333], ["Simon", 81.66666666666667]] 

Использует inject с аккумулятором, который изначально является 0. Затем добавить к нему каждый Num преобразуется в Float.

Бенчмаркинг:

require 'benchmark' 
arr = [["Timmy", "90", "47", "89"], ["Simon", "89", "57", "99"]] 
n = 1_000_000 
Benchmark.bm do |x| 
    x.report("map.inject : ") { n.times do ; arr.map do |name, *nums| ; [name, nums.map(&:to_f).inject(:+)/nums.length] ; end ; end } 
    x.report("inject(acc): ") { n.times do ; arr.map do |name, *nums|; [name, nums.inject(0){|ac,el| ac +el.to_f}/nums.length]; end ; end } 
end 

#=>  user  system  total  real 
#=> map.inject : 2.220000 0.000000 2.220000 ( 2.218477) 
#=> inject(acc): 2.030000 0.000000 2.030000 ( 2.031263) 
Смежные вопросы