【问题标题】:Map-reduce with escape clause for handling nils用于处理 nil 的带有转义子句的 Map-reduce
【发布时间】:2014-02-11 11:51:12
【问题描述】:

所以我正在编写一些代码来计算多段旅程中各种公共交通票选项的成本。这归结为计算每个段(地图)的成本并将它们相加(减少也称为注入),这很简单:

total = journey.map {|segment| compute segment}.reduce(:+)

问题是,有时compute 返回nil,因为该段对于给定的工单是不可能的,然后求和操作就会失败。在这种情况下,我想返回 nil,因为单个坏段意味着整个旅程无效。目前我正在这样做:

fares = journey.map {|segment| compute segment}
total = if fares.include? nil
  nil
else
  fares.reduce(:+)
end

我也可以写得简洁但(恕我直言)可读性较差:

fares = journey.map {|segment| compute segment}
total = fares.reduce{|sum, n| (sum.nil? or n.nil?) ? nil : sum + n}

但是必须有更好的方法,对吧...?

【问题讨论】:

    标签: ruby mapreduce inject


    【解决方案1】:

    我能想到的第一个“更好”的东西是:

    journey.map { |s| compute(s) }.reduce(0) do |sum, fee| 
      break nil unless fee
      sum + fee
    end
    

    更新:只要compute 返回nil,就会返回nil

    journey.reduce(0) do |sum, segment|
      fee = compute(segment)
      break nil unless fee
      sum + fee
    end
    

    【讨论】:

    • OP 的问题是,如果找到任何中间 nil 值,他/她不想进一步计算。
    • +1 用于中断而不是在 reduce 中携带 nil,但 Arup 是对的,在映射阶段中断会更好。虽然计算不是很昂贵,但我会接受一个漂亮的解决方案,即使它不是超级高效。
    • 更新版本有效:干净、易读、快速!复选标记是你的。
    【解决方案2】:

    如下操作:

    result = []
    journey.take_while { |segment| !(result << compute(segment)).include?(nil) }
    total = (result.size == journey.size)  ? result.inject(:+) : nil
    

    您可以使用Array#take_while 方法:

    将元素传递给块,直到块返回 nil 或 false,然后停止迭代并返回所有先前元素的数组。

    【讨论】:

    • 这与我的第一个解决方案相同,只是将 if-else 替换为三元。
    • @jpatokal 你得到这个答案了吗?否则请告诉我。
    • @ArupRakshit 注意compute segment,没有括号是语法错误。
    猜你喜欢
    • 2016-11-16
    • 1970-01-01
    • 2020-06-07
    • 2015-09-05
    • 2018-03-18
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    相关资源
    最近更新 更多