【问题标题】:Counting changes in an array计算数组中的变化
【发布时间】:2018-02-21 06:32:45
【问题描述】:

我想计算这个数组中"red" 后跟"green" 的次数:

["red", "orange", "green", "red", "yellow", "blue", "green"]

如果是另一种颜色,代码应该忽略它并继续到数组中的下一项。

event_type.each_slice(2) do |red, green|
  break unless green
  count = count + 1
end

p "The count is #{count}"

第一步:

Look for red

第二步:

IF not last item 
           Compare with next item on array
ELSE       Go to Step 4

第三步:

IF green, count = count + 1
          Go to Step 1
ELSE      Go to Step 2

第四步:

Print Count

【问题讨论】:

  • 如果绿色后跟红色,那么计数是 1?
  • 正在寻找红色后绿色的案例?
  • @RAJ 如果红变绿不算1
  • 为什么计数是 2?第一个"red" 更改为"orange",第二个更改为"yellow"。既不改变"green",也根据问题“如果它是另一种颜色,代码将忽略它”
  • 你能逐步解释一下算法吗?我看到的是"red",然后是(或更改为)"orange",然后是"green",依此类推。

标签: ruby counter


【解决方案1】:

这是著名的 Ruby 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

也测试过

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

FWIW,这是我在一周内回答的第二个问题,建议使用人字拖。以前的one is here


Stefan Pochmann 的清洁解决方案

input.count { |x| x == "green" if (x == "red")..(x == "green") }

【讨论】:

  • 您是否尝试过在逻辑混淆上下文中竞争?你有很大的潜力。 :trollface: 这段代码很容易生成两个WTFs。很好的练习,是的,但我不会把它放到生产代码中。我太笨了,以后看不懂:)
  • @marmeladze 或只是input.reduce(0) { |acc, (e, _)| ...} 以避免冗余映射。
  • @marmeladze,mudasobwa,但您在这里忽略了时间部分。相反,Joshua 想要进一步过滤匹配项(我认为只计算那些发生在 10 秒内的翻转)。不过,这绝对超出了这里的范围:)
  • @SergioTulentsev 你说你想要一个漂亮干净的foo if a..b 身体?没问题:input.count { |x| x == "green" if (x == "red")..(x == "green") }
  • 只需阅读链接的帖子,它就很棒。我希望有一天我记得用它来做一些事情,如果不是为了高效干净的代码,至少是为了让同事们感到困惑。
【解决方案2】:

以下是我相信的解决方案。当然还有更多的重构空间,你可以从这里开始。

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

更艺术的版本。

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

更新

感谢@Stefan 提供以下建议。

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))

更新

正如 Stefan Pochmann 所提议的,

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

会做同样的工作,而不需要另一个方法调用。

【讨论】:

  • 我应该在哪里添加计数才能打印出来?
  • 你可以用select { condition }代替reject { !condition }count { condition }代替select { condition }.size
  • 抱歉,您能指出输出计数的那一行吗?
  • count(['red', 'green']) 怎么样?
【解决方案3】:
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

【讨论】:

【解决方案4】:
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

【讨论】:

    猜你喜欢
    • 2020-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-04
    • 1970-01-01
    相关资源
    最近更新 更多