Counting changes in an array

☆樱花仙子☆ 提交于 2019-12-02 13:30:22

Below one is solution I believe. Sure there is more room to refactor it, you can start from here.

a = ["red", "orange", "green", "red", "yellow", "blue", "green"]    
a.reject {|e| !['red', 'green'].include? e }
  .each_cons(2)
  .select{|e| e == ['red', 'green']}
  .size

A more artistic version.

def neither_red_nor_green e
  !['red', 'green'].include? e
end

def red_followed_by_green ary
  ary == ['red', 'green']
end

a.reject(&method(:neither_red_nor_green))
  .each_cons(2)
  .select(&method(:red_followed_by_green))
  .size

UPDATE

Thanks to @Stefan for below suggestions.

def either_red_or_green e
  ['red', 'green'].include? e
end

def red_followed_by_green ary
  ary == ['red', 'green']
end


a.select(&method(:either_red_or_green))
  .each_cons(2)
  .count(&method(:red_followed_by_green))

UPDATE

As Stefan Pochmann proposed,

a.select(&method(:either_red_or_green))
  .each_cons(2)
  .count(['red', 'green'])

will do the same work, without needing another method call.

This is a perfect use-case for Ruby famous flip-flop:

input = %w[red orange green red yellow blue green]

input.reduce(0) do |count, e|
  if (e == "red")..(e == "green") and (e == "green")
    count + 1  # inc on right boundary
  else
    count
  end
end
#⇒ 2

Also tested on

%w[yellow green green red orange green red yellow blue green red yellow]

FWIW, this is a second question I answered suggesting the flip-flop in a week. The previous one is here.


Clean solution from Stefan Pochmann

input.count { |x| x == "green" if (x == "red")..(x == "green") }
count, _ =
["red", "orange", "green", "red", "yellow", "blue", "green"]
.inject([0, nil]) do |(count, state), word|
  if word == "red"
    state = :red
  elsif word == "green" and state == :red
    state = nil
    count += 1
  end
  [count, state]
end
count # => 2
def count_red_to_green(arr)
  count = 0
  unmatched_red = false
  arr.each do |colour|
    case colour
    when "red"
      unmatched_red = true
    when "green"
      if unmatched_red
        count += 1
        unmatched_red = false
      end
    end
  end
  count
end

count_red_to_green ["red", "orange", "green", "red", "yellow", "blue", "green"]
  #=> 2
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!