Как посчитать последовательные числа в массиве? - PullRequest
3 голосов
/ 07 мая 2019

Если у меня есть массив:

array = [1,2,2,2,2,5,5,1,1,1,3,3,3,3,2,2,2,2,2,2,2]

Я хочу иметь возможность идентифицировать последовательные совпадающие номера, длина которых превышает 3. И отобразить начальный индекс последовательных чисел.Пример вывода для вышеуказанного массива:

consecutive_numbers = [
  {starting_index: 1, value: 2, length: 4},
  {starting_index: 10, value: 3, length: 4},
  {starting_index: 14, value: 2, length: 7}
]

Значения могут быть одинаковыми, но последовательный ряд должен быть взаимоисключающим.Посмотрите, что есть 2 хэша со значением 2, но их начальные индексы разные.

Моя попытка до сих пор ... выглядит следующим образом:

array.each_cons(3).with_index.select{|(a,b,c), i| 
  [a,b,c].uniq.length == 1
}

, но это вернет:

[[[2, 2, 2], 1], [[2, 2, 2], 2], [[1, 1, 1], 7], [[3, 3, 3], 10], [[3, 3, 3], 11], [[2, 2, 2], 14], [[2, 2, 2], 15], [[2, 2, 2], 16], [[2, 2, 2], 17], [[2, 2, 2], 18]]

Но это возвращает перекрывающиеся результаты.

Ответы [ 5 ]

4 голосов
/ 07 мая 2019
array.each_with_index.
      chunk(&:first).
      select { |_,a| a.size > 3 }.
      map { |n,a| { starting_index: a.first.last, value: n, length: a.size } }
  #=> [{:starting_index=> 1, :value=>2, :length=>4},
  #    {:starting_index=>10, :value=>3, :length=>4},
  #    {:starting_index=>14, :value=>2, :length=>7}] 

Шаги следующие:

e = array.each_with_index.chunk(&:first)
  #=> #<Enumerator: #<Enumerator::Generator:0x00005b1944253c18>:each> 

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

e.to_a
  #=> [[1, [[1, 0]]],
  #    [2, [[2, 1], [2, 2], [2, 3], [2, 4]]],
  #    [5, [[5, 5], [5, 6]]],
  #    [1, [[1, 7], [1, 8], [1, 9]]],
  #    [3, [[3, 10], [3, 11], [3, 12], [3, 13]]],
  #    [2, [[2, 14], [2, 15], [2, 16], [2, 17], [2, 18], [2, 19], [2, 20]]]] 

Продолжая,

c = e.select { |_,a| a.size > 3 }
  #=> [[2, [[2, 1], [2, 2], [2, 3], [2, 4]]],
  #    [3, [[3, 10], [3, 11], [3, 12], [3, 13]]],
  #    [2, [[2, 14], [2, 15], [2, 16], [2, 17], [2, 18], [2, 19], [2, 20]]]] 
c.map { |n,a| { starting_index: a.first.last, value: n, length: a.size } }
  #=> [{:starting_index=> 1, :value=>2, :length=>4},
  #    {:starting_index=>10, :value=>3, :length=>4},
  #    {:starting_index=>14, :value=>2, :length=>7}] 

Это другой путь.

array.each_with_index.with_object([]) do |(n,i),arr|
  if arr.any? && arr.last[:value] == n
    arr.last[:length] += 1
  else
    arr << { starting_index: i, value: n, length: 1 }
  end
end.select { |h| h[:length] > 3 }
  #=> [{:starting_index=> 1, :value=>2, :length=>4},
  #    {:starting_index=>10, :value=>3, :length=>4},
  #    {:starting_index=>14, :value=>2, :length=>7}]     
2 голосов
/ 07 мая 2019

Это еще один вариант ..


array
     .zip(0..)
     .slice_when { |a, b| a.first != b.first }
     .map { |a| { starting_index: a.first.last, value: a.first.first, length: a.size } }
     .reject { |h| h[:length] < 3 }

#=> [{:starting_index=>1, :value=>2, :length=>4}, {:starting_index=>7, :value=>1, :length=>3}, {:starting_index=>10, :value=>3, :length=>4}, {:starting_index=>14, :value=>2, :length=>7}]
2 голосов
/ 07 мая 2019

Вы можете chunk_while каждая пара элементов равны:

p array.chunk_while { |a, b| a == b }.to_a
# [[1], [2, 2, 2, 2], [5, 5], [1, 1, 1], [3, 3, 3, 3], [2, 2, 2, 2, 2, 2, 2]]

Вы выбираете массивы с 3 или более элементами.

После этого, с помощью then, вы можете привести к самому себе , так что у вас есть доступ к массиву массивов, который вы можете использовать для получения starting_index:

[1,2,2,2,2,5,5,1,1,1,3,3,3,3,2,2,2,2,2,2,2].chunk_while(&:==).then do |this|
  this.each_with_object([]).with_index do |(e, memo), index|
    memo << { starting_index: this.to_a[0...index].flatten.size, value: e.first, length: e.size }
  end
end.select { |e| e[:length] > 3 }

# [{:starting_index=>1, :value=>2, :length=>4},
#  {:starting_index=>10, :value=>3, :length=>4},
#  {:starting_index=>14, :value=>2, :length=>7}]

Для начального индекса вы получаете элементы для текущего индекса (не включительно), выравниваете их и получаете общее количество элементов.

Значение, поскольку каждый массив в массиве имеет одинаковые элементы, может быть любым, длина - длина текущего массива в «основном» массиве.

0 голосов
/ 07 мая 2019

Вместо этого вы можете работать со строками.

Здесь я приведу массив в строку:

input_sequence = [1,2,2,2,2,5,5,1,1,1,3,3,3,3,2,2,2,2,2,2,2].join

Я использую регулярное выражение для группировки последовательных символов:

groups = input_sequence.gsub(/(.)\1*/).to_a
#=> ["1", "2222", "55", "111", "3333", "2222222"]

Теперь я могу искать группы как подстроки во входной строке:

groups.map do |group|
  {
    starting_index: input_sequence.index(group), 
    value: group[0].to_i,
    length: group.length
  }
end.reject { |group| group[:length] <= 3 }

#=> [{:starting_index=>1, :value=>2, :length=>4},
     {:starting_index=>7, :value=>1, :length=>3},
     {:starting_index=>10, :value=>3, :length=>4},
     {:starting_index=>14, :value=>2, :length=>7}]

Здесь есть место для улучшения - я создаю множество промежуточных объектов для одного - но я подумал, что будупредложить другой подход.

0 голосов
/ 07 мая 2019

Ну, самый очевидный (и, вероятно, самый быстрый) способ - это итерация по массиву и подсчет всего вручную:

array = [1,2,2,2,2,5,5,1,1,1,3,3,3,3,2,2,2,2,2,2,2]
array_length_pred = array.length.pred

consecutive_numbers = []

starting_index = 0
value = array.first
length = 1

array.each_with_index do |v, i|
  if v != value || i == array_length_pred
    length += 1 if i == array_length_pred && value == v

    if length >= 3
      consecutive_numbers << {
        starting_index: starting_index,
        value: value,
        length: length
      }
    end

    starting_index = i
    value = v
    length = 1
    next
  end

  length += 1
end

p consecutive_numbers

# [{:starting_index=>1, :value=>2, :length=>4},
# {:starting_index=>7, :value=>1, :length=>3},
# {:starting_index=>10, :value=>3, :length=>4},
# {:starting_index=>14, :value=>2, :length=>7}]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...