【问题标题】:How to write down these three cases in a more elegant way?如何用更优雅的方式写下这三个案例?
【发布时间】:2012-11-09 14:17:49
【问题描述】:

是否有可能使这段代码更紧凑?我在这里错过了什么吗?

    if value < min_rate
      min_rate
    elsif value > max_rate
      max_rate
    else
      value
    end

【问题讨论】:

  • 这告诉读者究竟发生了什么以及它是如何发生的。我更喜欢这种方式。
  • Stack Exchange 的"codereview" 网站是这类问题的新热点。

标签: ruby coding-style conditional-statements


【解决方案1】:

这是完全不同的东西:

[min_rate, value, max_rate].sort[1]

【讨论】:

  • 对我来说看起来很简单,还是说计算成本很高?在典型的用例中,对可能已经排序或最坏情况下需要一次交换的 3 元素数组进行排序不会是一个重大的性能问题。除非你在一个大循环中这样做。
  • 是的,它是大循环的一部分,因此计算可能会成为问题
  • 在我的基准测试中,它需要循环大小为 2000000 才能产生一秒的差异。
  • 你说得对,我改变了主意。我对[0, partner_rate, max_rate].sort[1] 很满意。谢谢你:)
  • 如果我在实际代码中遇到这种情况,我会找到作者并为他过于聪明打耳光,然后重构它。理解这个 sn-p 所做的事情(弄清楚排序如何与各种可能性相互作用并说服自己中间值将是原始值或适当的界限)的认知负荷对于决策的固有复杂性来说太高了。如果将它分解为一个有名的小方法,它可能是可以接受的,但作为循环中间的简单保护计算,它很臭。然而,这是一个聪明的代码高尔夫。
【解决方案2】:

对我来说,这看起来更具可读性和易于理解。希望你喜欢。

def some_method    
  return min_rate if value < min_rate
  return max_rate if value > max_rate

  value
end

【讨论】:

  • 这也是解决这个问题的好方法,但它很好地解释了代码中发生的事情
  • @NickShebanov 我不这么认为它很好地解释了代码。如果您的代码中有很多 iffing,那么您必须将代码分成小方法,并为每个方法进行条件检查。 Iffing 增加了代码的复杂性,变得不易阅读和理解。
【解决方案3】:

max(min(value, max_rate), min_rate)。这将分别隐藏 minmax 内的 if 分支(“iffing”?)。

【讨论】:

  • 这看起来不错,但默认情况下全局范围内没有 max/min 方法。
  • 是的,我同意@NickShebanov,全局范围内没有最大/最小方法。但是,如果您愿意,您可以执行 [[value, max_rate].min, min_rate].max 之类的操作,但由此您无法区分哪个值大于或小于其他值。
  • 带数组的选项只解决了代码大小问题,但给代码带来了复杂性(计算和可读性),所以这不是我想要的。
【解决方案4】:

三元赋值“更紧凑”,但绝对不是更漂亮:

value = (value < min_rate) ? min_rate : (value > max_rate) ? max_rate : value

【讨论】:

  • 是的,漂亮很重要。三元运算符是首先想到的。
  • Ruby 允许将三元表达式分布在多行中,方法是将?: 放在行尾:value = (value &lt; min_rate) ?\n min_rate :\n (value &gt; max_rate) ?\n max_rate :\n value。将其复制到编辑器中并将\n 替换为换行符以获得完整效果。在 Perl 中,我们会使用一些非常复杂的三元组,但通过适当的缩进,它非常可读和可维护。
【解决方案5】:

你需要的是嵌套三元运算符

value < min_rate ? min_rate :
value > max_rate ? max_rate :
value

这样就可以了 如果您愿意,您可以将所有内容放在一行中,这样做只是为了便于阅读

【讨论】:

    【解决方案6】:

    嗯,我同意@pwned,但有一种更优雅的做法。恕我直言,也是一样,但阅读效果更好。

      def calculate(value)
        return min_rate if value < min_rate
        return max_rate if value > max_rate
        value
      end
    

    我根本不喜欢那种层叠风格。 =)

    【讨论】:

    • 我也不喜欢级联风格,除非 if 被用作表达性三元运算符来返回一个值,这就是在这种情况下发生的情况。
    【解决方案7】:

    您可以尝试使用实用方法扩展 Range:

    module RangeHelper
      def bound value
        value < self.begin ? self.begin :
        value > self.end   ? self.end :
        value
      end
    end
    Range.class_eval { include RangeHelper }
    
    (1..10).bound 5  # => 5
    (1..10).bound -5 # => 1
    (1..10).bound 15 # => 10
    

    【讨论】:

    • 除了我之外还有人觉得这个 std ruby​​ 类的方法名称与关键字冲突吗?
    • 我满足于使用不与关键字冲突的“first”和“last”。
    • @pwned 由于firstlast 接受一个N 参数,我假设它们不是完全等效的并且可能效率低得多,因为它们将在Range#each 上实现。现在检查源代码,我发现对于无参数调用,它们基本上等同于 #begin#end
    【解决方案8】:
    class Range
      def limit(value)
        if value> last
          last
        elsif value< first
          first
        else
          value
        end
      end
    end
    
    p (-50..50).map{ |n| (10..20).limit(n) }.uniq== (10..20).to_a
    

    $ 真

    【讨论】:

      【解决方案9】:

      自 Ruby 2.4(2016 年 12 月)以来,我们有一种方法可以做到这一点:Comparable#clamp:

      value = 15
      value.clamp(10, 20) # => 15
      value.clamp(0, 10) # => 10
      value.clamp(20, 30) # => 20
      

      由于它是 Comparable 的一部分,它适用于任何包含 Comparable 的类,例如:

      "foo".clamp("bar", "baz") # => "baz"
      

      【讨论】:

        猜你喜欢
        • 2015-03-03
        • 1970-01-01
        • 2012-08-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多