【问题标题】:Breaks within Each and If statements not behaving quite how I want them to in RubyEach 和 If 语句中的中断与我在 Ruby 中的行为不太一样
【发布时间】:2013-10-04 22:04:42
【问题描述】:

在下面的代码中,我的期望是 :key2 或 :key5 由于第二个 elsif 语句而被分配 "1",但是我的代码似乎改为运行最终的 else 语句.我的break 语句没有放在正确的位置吗?

每当运行此代码时,我只希望它替换一个值并结束。

hash = { :key1 => "3", :key2 => "3", :key3 => "3", :key4 => "3", :key5 => "3", :key6 => "3", :key7 => "3", :key8 => "2", :key9 => "3"}   

array = [[:key1, :key2, :key3], [:key4, :key5, :key6], [:key7, :key8, :key9], [:key1,         :key4, :key7], [:key2, :key5, :key8],[:key3, :key6, :key9], [:key1, :key5, :key9], [:key3, :key5, :key7]]
array.each do |x|
if hash.values_at(*x).count("1") == 2 and hash.values_at(*x).count("3") == 1
    x.each do |x|
        if hash[x] == "3"
            hash[x] = "1"
        break
        end

    end
    break

    elsif hash.values_at(*x).count("2") == 2 and hash.values_at(*x).count("3") == 1
        x.each do |e|
            if hash[e] == "3"
                hash[e] = "1"
            break
            end

        end
        break
     elsif hash.values_at(*x).count("1") == 1 and hash.values_at(*x).count("3") == 2
        x.each do |g|
            if hash[g] == "3"
                hash[g] = "1"
            break
            end
        end
        break
     elsif hash.values_at(*x).count("3") == 3
        x.each do |h|
            if hash[h] == "3"
                hash[h] = "1"
                break
            end
        end
        break

else

end
end

【问题讨论】:

  • 你需要看看case 语句是如何工作的。看来您正在尝试重新设计 if 的工作方式,使其行为类似于 case/when,或者可能是嵌套的 case 语句。
  • 您还在第 6 行隐藏了一个外部变量,x.each do |x| 这并不是真正要做的事情。
  • case 会按顺序运行它们吗?我基本上希望它们按顺序运行,如果其中一个键更改为“1”,那么我希望循环中断@theTinMan
  • 是的,不要隐藏变量名。如果变量名可能比单个字符长,请使用一些更具描述性的名称。
  • case 将以与if 相同的顺序运行它们。逻辑从顶部开始并贯穿始终,检查条件。

标签: ruby arrays if-statement hash break


【解决方案1】:

这是用更好的空格重新组织的代码:

hash = {
  :key1 => "3",
  :key2 => "3",
  :key3 => "3",
  :key4 => "3",
  :key5 => "3",
  :key6 => "3",
  :key7 => "3",
  :key8 => "2",
  :key9 => "3"
}   

array = [
  [:key1, :key2, :key3],
  [:key4, :key5, :key6],
  [:key7, :key8, :key9],
  [:key1, :key4, :key7],
  [:key2, :key5, :key8],
  [:key3, :key6, :key9],
  [:key1, :key5, :key9],
  [:key3, :key5, :key7]
]

array.each do |key_set|

  if hash.values_at(*key_set).count("1") == 2 and hash.values_at(*key_set).count("3") == 1

    key_set.each do |x|

      if hash[x] == "3"
        hash[x] = "1"
        break
      end

    end
    break

  elsif hash.values_at(*key_set).count("2") == 2 and hash.values_at(*key_set).count("3") == 1

    key_set.each do |e|

      if hash[e] == "3"
        hash[e] = "1"
        break
      end

    end
    break

  elsif hash.values_at(*key_set).count("1") == 1 and hash.values_at(*key_set).count("3") == 2

    key_set.each do |g|

      if hash[g] == "3"
        hash[g] = "1"
        break
      end

    end
    break

  elsif hash.values_at(*key_set).count("3") == 3

    key_set.each do |h|

      if hash[h] == "3"
        hash[h] = "1"
        break
      end

    end
    break

  else

  end

end

这里改进了变量名称,并将 and 替换为 && 加上一些括号以直观地显示条件中的逻辑组:

array.each do |key_set|

  case
  when (hash.values_at(*key_set).count("1") == 2) && (hash.values_at(*key_set).count("3") == 1)

    key_set.each do |_key|

      if hash[_key] == "3"
        hash[_key] = "1"
        break
      end

    end
    break

  when (hash.values_at(*key_set).count("2") == 2) && (hash.values_at(*key_set).count("3") == 1)

    key_set.each do |_key|

      if hash[_key] == "3"
        hash[_key] = "1"
        break
      end

    end
    break

  when (hash.values_at(*key_set).count("1") == 1) && (hash.values_at(*key_set).count("3") == 2)

    key_set.each do |_key|

      if hash[_key] == "3"
        hash[_key] = "1"
        break
      end

    end
    break

  when (hash.values_at(*key_set).count("3") == 3)

    key_set.each do |_key|

      if hash[_key] == "3"
        hash[_key] = "1"
        break
      end

    end
    break

  else

  end

end

有大量的冗余和缺乏“干性”。 “DRY”代表“Don't Repeat Yourself”,意思是减少重复代码。

_key = key_set.find{ |k| hash[k] == '3' }
hash[_key] = '1' if _key
break

看起来是一个合理的替代品:

    key_set.each do |_key|

      if hash[_key] == "3"
        hash[_key] = "1"
        break
      end

    end
    break

所以将代码替换为:

array.each do |key_set|

  case
  when (hash.values_at(*key_set).count("1") == 2) && (hash.values_at(*key_set).count("3") == 1)

    _key = key_set.find{ |k| hash[k] == '3' }
    hash[_key] = '1' if _key
    break

  when (hash.values_at(*key_set).count("2") == 2) && (hash.values_at(*key_set).count("3") == 1)

    _key = key_set.find{ |k| hash[k] == '3' }
    hash[_key] = '1' if _key
    break

  when (hash.values_at(*key_set).count("1") == 1) && (hash.values_at(*key_set).count("3") == 2)

    _key = key_set.find{ |k| hash[k] == '3' }
    hash[_key] = '1' if _key
    break

  when (hash.values_at(*key_set).count("3") == 3)

    _key = key_set.find{ |k| hash[k] == '3' }
    hash[_key] = '1' if _key
    break

  else

  end

end

每个when 都是多余的,因此可以将它们移到case 上方:

array.each do |key_set|

  _key = key_set.find{ |k| hash[k] == '3' }
  hash[_key] = '1' if _key

  case
  when (hash.values_at(*key_set).count("1") == 2) && (hash.values_at(*key_set).count("3") == 1)
    break

  when (hash.values_at(*key_set).count("2") == 2) && (hash.values_at(*key_set).count("3") == 1)
    break

  when (hash.values_at(*key_set).count("1") == 1) && (hash.values_at(*key_set).count("3") == 2)
    break

  when (hash.values_at(*key_set).count("3") == 3)
    break

  else

  end

end

puts hash

再减少一点会导致:

array.each do |key_set|

  _key = key_set.find{ |k| hash[k] == '3' }
  hash[_key] = '1' if _key

  case
  when (hash.values_at(*key_set).count("1") == 2) && (hash.values_at(*key_set).count("3") == 1), 
      (hash.values_at(*key_set).count("2") == 2) && (hash.values_at(*key_set).count("3") == 1),
      (hash.values_at(*key_set).count("1") == 1) && (hash.values_at(*key_set).count("3") == 2),
      (hash.values_at(*key_set).count("3") == 3)
    break

  else

  end

end

puts hash

与其他所有输出一样,输出:

{:key1=>"1", :key2=>"3", :key3=>"3", :key4=>"3", :key5=>"3", :key6=>"3", :key7=>"3", :key8=>"2", :key9=>"3"}

第一个代码中有很多代码可以完成最后一个代码的工作。而且,还有更多的 DRYing 可以做,但我会留给你来解决。

【讨论】:

  • 谢谢,我在第二个when 中添加了一个puts 并将key8 更改为“1”,期待我的puts 但是我收到了puts 我包含在最后的when .编辑:我会检查我的代码,直到它表现最佳。
  • @RavensFlock - 在@TimMan 的精简代码中只有一个when。当您说“最终何时”时,您指的是什么?
  • 看完这个之后,我明白我在哪里搞砸了,但我该怎么做才能遍历所有数组key_set,最后只执行(hash.values_at(*key_set).count("3") == 3) 和以下代码,如果没有数组可以满足前面的任何情况。 @the-tin-man @petet-alfivin
【解决方案2】:

您的哈希中没有除"3" 之外的值,因此除了最后一个elsif 之外,您的任何条件最初都不会成功,因为它们都需要存在除"3" 之外的值。在最后一个elsif 的主体中,您将hash[key1] 重新定义为"1",然后您将break 从内部each 中取出,然后将break 从外部每个中取出,终止执行。没有其他事情发生。

【讨论】:

  • 对不起,:key8 应该是“2”。但是,当我运行它时:key1 始终设置为“1”
  • 没关系。这仍然只给你一个“2”,而不是你的条件要求的两个,所以结果是一样的。
【解决方案3】:

这是一些...有趣的代码。我绝对建议简化以帮助调试,但这就是正在发生的事情。

  1. 输入array.each
  2. elsif hash.values_at(*x).count("3") == 3点击
  3. 你玩一下哈希,然后爆发
  4. 你突破array.each
  5. 完成。

小步,puts 电话是您的朋友。

【讨论】:

  • 我只是在学习编码,所以我知道这不是最好的。我希望一旦我开始工作,我就可以折射。
猜你喜欢
  • 2013-10-11
  • 2016-01-02
  • 2011-12-01
  • 2013-05-04
  • 1970-01-01
  • 2019-06-30
  • 1970-01-01
  • 1970-01-01
  • 2014-10-24
相关资源
最近更新 更多