Вычислить пропущенные значения в массиве из соседних значений - PullRequest
2 голосов
/ 31 декабря 2010

Учитывая массив

[50,30,0,0,10,0,30,60,0]

Мне нужно заменить нули на вычисленные значения, чтобы создать 'кривая », так что, например, между 10 и 30 ноль можно заменить на 20.

Я продолжаю думать, что должен быть крутой рубиновый способ сделать это, но я не могу его найти.Кто-нибудь может помочь?Решение должно учитывать несколько смежных нулей и нулей в начале и в конце диапазона.

У кого-нибудь есть идеи?

Ответы [ 5 ]

2 голосов
/ 31 декабря 2010

Термин, о котором вы, похоже, не подозреваете, - интерполяция .Хорошим местом для начала является статья в Википедии - то, какой алгоритм лучше всего подходит вам, зависит от точного контекста вашей проблемы, поэтому мы не можем дать вам единственно верный ответ.

1 голос
/ 31 декабря 2010

Если бы не было последовательных нулей, этот неразборчивый однострочный выполнил бы трюк (list - данный список чисел):

[0, *list, 0].each_cons(3).map { |p, x, n| x == 0 ? (p + n)/2 : x }

Только Ruby 1.9, я думаю.*

1 голос
/ 31 декабря 2010
a =[50,30,0,0,10,0,30,60,0]

a.each_index{|i| a[i] = a[i-1] - ((a[i-2] - a[i-1])/2).to_i if a[i] == 0 && i > 1 }

puts a.inspect # [50, 30, 20, 15, 10, 8, 30, 60, 75]

Я не могу понять, почему последний номер может быть 80 в вашей спецификации, однако? Кроме того, он не работает для первых двух элементов в массиве.

0 голосов
/ 22 июля 2013

Просто наткнулся на этот вопрос. Существует рубиновый гем "интерполятор", который просто делает то, что вы хотите, и, вероятно, еще больше:

http://interpolator.rubyforge.org.

Вот краткое введение:

http://fabianosoriani.wordpress.com/2010/02/23/ruby-interpolation-with-gem-interpolator/

0 голосов
/ 31 декабря 2010
def find_consecutive_values( array, value=nil )
  raise "Need a value or block to find" unless value || block_given?
  start = last = nil
  ranges = []
  indices = array.each_with_index do |o,i|
    if ((block_given? && yield(o)) || o==value)
      start = i unless start
      last = i
    else
      ranges << (start..last) if start && last
      start = last = nil
    end
  end
  ranges << (start..last) if start && last
  ranges
end

def interpolate_zeros( array, round=false )
  result = array.dup
  find_consecutive_values( array, 0 ).each do |range|
    next unless range.first>0 && range.last<(array.length-1)
    before = result[range.first - 1]
    after  = result[range.last  + 1]
    diff   = after - before
    size   = (range.last - range.first + 2).to_f
    range.each_with_index do |i,idx|
      value = before + diff * (idx+1)/size
      value = value.round if round
      result[i] = value
    end
  end
  result
end

p interpolate_zeros( [0,50,30,0,0,10,0,30,60,0], true )
#=> [0, 50, 30, 23, 17, 10, 20, 30, 60, 0]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...