Выберите диапазон значений из массива, включая дубликаты - PullRequest
0 голосов
/ 10 января 2019

Мне дан массив arr целых чисел, отсортированный в порядке возрастания или убывания. Если arr содержит хотя бы два отдельных элемента, мне нужно найти самый длинный arr.last(n), который имеет ровно два различных элемента (то есть с наибольшим n). В противном случае он должен вернуть arr. Вот некоторые примеры:

  • arr = [6, 4, 3, 2, 2], затем [3, 2, 2] подлежит возврату
  • arr = [6, 4, 3, 3, 2], затем [3, 3, 2] подлежит возврату
  • arr = [1], затем arr подлежит возврату.

Буду признателен за предложения о том, как вычислить желаемый результат.

Ответы [ 3 ]

0 голосов
/ 10 января 2019
def last_two_different(arr, count)
  arr.reverse_each.
      lazy.
      chunk(&:itself).
      first(count).
      flat_map(&:last).
      reverse
end

last_two_different [6, 4, 3, 2, 2], 2  #=> [3, 2, 2] 
last_two_different [3, 4, 3, 3, 2], 2  #=> [3, 3, 2]
last_two_different [3, 4, 3, 3, 2], 3  #=> [4, 3, 3, 2] 
last_two_different [3, 4, 3, 3, 2], 4  #=> [3, 4, 3, 3, 2] 
last_two_different [1, 2], 2           #=> [1, 2]
last_two_different [1, 1], 2           #=> [1, 1] 
last_two_different [1], 2              #=> [1] 
last_two_different [], 2               #=> [] 

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

arr = [6, 4, 3, 2, 2]
count = 2

enum0 = arr.reverse_each
  #=> #<Enumerator: [6, 4, 3, 2, 2]:reverse_each> 

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

enum0.to_a
  #=> [2, 2, 3, 4, 6] 

Сначала предположим, что мы написали следующее.

enum1 = enum0.chunk(&:itself)
  #=> #<Enumerator: #<Enumerator::Generator:0x00005c29be132b00>:each> 
enum1.to_a
  #=> [[2, [2, 2]], [3, [3]], [4, [4]], [6, [6]]] 

Нам нужны первые count #=> 2 элементы, сгенерированные enum1, из которых мы могли бы извлечь желаемый результат. Это говорит нам о том, что нам нужен ленивый перечислитель.

enum2 = enum0.lazy
  #=> #<Enumerator::Lazy: #<Enumerator: [6, 4, 3, 2, 2]:reverse_each>> 
enum3 = enum2.chunk(&:itself)
  #=> #<Enumerator::Lazy: #<Enumerator:
  #     #<Enumerator::Generator:0x00005c29bdf48cb8>:each>>
enum3.to_a
  #=> [[2, [2, 2]], [3, [3]], [4, [4]], [6, [6]]] 

a = enum3.first(count)
  #=> [[2, [2, 2]], [3, [3]]] 
b = a.flat_map(&:last)
  #=> [2, 2, 3] 
b.reverse
  #=> [3, 2, 2] 
0 голосов
/ 10 января 2019

Не уверен насчет эффективности, но вот еще один способ сделать это:

arr = [6, 4, 3, 2, 2]
uniq = arr.uniq.last(2) # => [3, 2]
arr.select{|e| uniq.include?(e)} # => [3, 2, 2]
0 голосов
/ 10 января 2019

Вот довольно неэффективный подход, который использует take_while:

def last_non_dupe(array, count = 2)
  result = [ ]
  array.reverse.take_while do |n|
    result << n
    result.uniq.length <= count
  end.reverse
end

Его можно улучшить, используя Set, который автоматически уникален:

require 'set'

def last_non_dupe(array, count = 2)
  result = Set.new
  array.reverse.take_while do |n|
    result << n
    result.length <= count
  end.reverse
end

Где в любом случае вы делаете:

last_non_dupe([6, 4, 3, 2, 2])
# => [3, 2, 2]

Аргумент count может быть изменен по мере необходимости для более длинных или более коротких списков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...