Select value range from an array, including duplicates

时间:2019-01-09 22:30:21

标签: arrays ruby

I am given an array arr of integers that is sorted in ascending or descending order. If arr contains at least two distinct elements, I need to find the longest arr.last(n) that has exactly two distinct elements (i.e., with the largest n). Otherwise, it should return arr. Some examples are:

  • arr = [6, 4, 3, 2, 2], then [3, 2, 2] is to be returned
  • arr = [6, 4, 3, 3, 2], then [3, 3, 2] is to be returned
  • arr = [1], then arr is to be returned.

I would be grateful for suggestions on how to compute the desired result.

3 个答案:

答案 0 :(得分:4)

这里使用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参数。

答案 1 :(得分:3)

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] 

答案 2 :(得分:3)

不确定效率,但这是另一种实现方法:

arr = [6, 4, 3, 2, 2]
uniq = arr.uniq.last(2) # => [3, 2]
arr.select{|e| uniq.include?(e)} # => [3, 2, 2]