Как определить вершины и впадины в массиве поплавков? - PullRequest
0 голосов
/ 06 марта 2019

у меня есть массив,

array = [
  0.43, 
  0.64, # => peak
  0.2, 
 -0.05, 
 -0.15, # => trough
  0.2, # => peak
 -0.1, 
 -0.5, # => trough
 -0.3
]

, который имеет два пика и два впадины в данных. Эти пики и впадины не обязательно являются min и max массива. Как определить их по программе?

Идеальный результат будет:

peak_indexes = [1, 5]
trough_indexes = [4, 7]

Ответы [ 3 ]

2 голосов
/ 06 марта 2019

each_cons(3) извлекает три смежных термина, необходимых для проверки среднего, исключая тройки с первым или последним элементом array в середине.

with_index(1) учитывает тот факт, что триплет с первым элементом, равным array в середине, был пропущен, поэтому нумерация индексов начинается с 1.

Вы не определили, что вы подразумеваете под пиками и впадинами. Если вы хотите взять локальные значения max и min, то сработает следующее.

array.each_cons(3).with_index(1).select{|a, i| a.max == a[1]}.map(&:last)
# => [1, 5]

array.each_cons(3).with_index(1).select{|a, i| a.min == a[1]}.map(&:last)
# => [4, 7]

Или, если вы имеете в виду то, что Стефан объясняет в комментарии к моему ответу, тогда сработает следующее:

array
.each_cons(3)
.with_index(1)
.select{|(a1, a2, a3), i| a1 < a2 && a2 > a3}
.map(&:last)
# => [1, 5]

array
.each_cons(3)
.with_index(1)
.select{|(a1, a2, a3), i| a1 > a2 && a2 < a3}
.map(&:last)
# => [4, 7]
1 голос
/ 06 марта 2019

Сначала давайте определим, что значит быть вершиной или впадиной.

  • Пик - это значение, которое БОЛЬШЕ, чем значение слева и справа.
  • Корыто - это значение, которое МЕНЬШЕ, чем значение слева и справа.

Это позволит нам определить две полезные функции:

def is_peak?(left_value, value, right_value)
  return value > left_value && value > right_value
end

def is_trough?(left_value, value, right_value)
  return value < left_value && value < right_value
end

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

array = [0.43, 0.64, 0.2, -0.05, -0.15, 0.2, -0.1, -0.5]
positive_peak_indexes = []
negative_peak_indexes = []
# Loop through the array
array.each_with_index do |elem, i|
  # Make sure we don't get an out of bounds exception
  next if (i-1 < 0) || (i + 1 >= array.length)

  # Now we add to our appropriate arrays if it's a peak/trough
  positive_peak_indexes << i if is_peak?(array[i-1], elem, array[i+1])
  negative_peak_indexes << i if is_trough?(array[i-1], elem, array[i+1])
end
puts "positive_peak_indexes = #{positive_peak_indexes.to_s}"
puts "negative_peak_indexes = #{negative_peak_indexes.to_s}"
0 голосов
/ 06 марта 2019

У меня не было времени протестировать больше случаев, поэтому, возможно, есть какая-то ошибка.

В любом случае, основная идея состоит в том, чтобы сжать каждый элемент с его индексом ( Enumerable # each_with_index ), затем используйте метод Enumerable # chunk_ while , чтобы разделить массив при изменении.Наконец, извлеките из фрагментов крайние значения.

Лучше с куском кода, ary - это массив данных.

Сначала фрагменты:

chunks = ary.map.with_index{ |x, i| [x,i] }.chunk_while { |x,y| y.first < x.first }

Затемсобери крайности:

peaks = chunks.collect { |e| e.first if e.size > 1 }.compact #=> [[0.64, 1], [0.2, 5]]
trough = chunks.collect { |e| e.last if e.size > 1 }.compact #=> [[-0.15, 4], [-0.5, 7]]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...