如果在 1 行中返回的值为 0,我如何优雅地返回 1.0?

mar*_*ion 3 ruby ruby-on-rails-5

我有这样的声明:

> zv.sum(:volume).to_f || 1.0
   (0.5ms)  SELECT SUM("positions"."volume") FROM "positions" WHERE "positions"."volume" = $1  [["volume", 0]]
=> 0.0
Run Code Online (Sandbox Code Playgroud)

我想要发生的是 ifzv.sum(:volume)返回0.0,我希望它返回1.0

我知道我可以做一个冗长的if/unless语句,但我想在上面的 1 行中优雅地做它。

我怎么做?

Jör*_*tag 5

您的标题和问题中确实有解决方案(我的粗体强调):

如果在 1 行中返回的值为 0,我如何优雅地返回 1.0 ?

我想要发生的是ifzv.sum(:volume)返回0.0,我希望它返回1.0

因此,最好的方法是使用条件表达式

sum = zv.sum(:volume).to_f

if sum == 0.0
  1.0
else
  sum
end
Run Code Online (Sandbox Code Playgroud)

如果你想“优化”这个,你可以将转换移动到浮动到表达式的最边缘:

sum = zv.sum(:volume)

if sum == 0
  1
else
  sum
end.to_f
Run Code Online (Sandbox Code Playgroud)

[注意,这假设 的值zv.sum(:volume)将是一个数字,而不是类似nil或代表数字的字符串。如果可以保证,同样的转换也可以应用于以下每个示例。]

在 Ruby 中总是可以轻松实现在 1 行中做某事的要求,因为换行符始终是可选的。例如:

sum = zv.sum(:volume).to_f; if sum == 0.0 then 1.0 else sum end
Run Code Online (Sandbox Code Playgroud)

或者,如果您想避免使用关键字:

sum = zv.sum(:volume).to_f; if sum == 0.0; 1.0 else sum end
Run Code Online (Sandbox Code Playgroud)

还有条件运算符,但就我个人而言,我认为它不能(更好)由条件表达式提供服务:

sum = zv.sum(:volume).to_f; sum == 0.0 ? 1.0 : sum
Run Code Online (Sandbox Code Playgroud)

如果你想要一个单一的表达式,你可以将变量赋值内联到条件中:

if (sum = zv.sum(:volume).to_f) == 0.0
  1.0
else
  sum
end
Run Code Online (Sandbox Code Playgroud)

当然,您可以将两者结合起来:

if (sum = zv.sum(:volume).to_f) == 0.0 then 1.0 else sum end
Run Code Online (Sandbox Code Playgroud)

并避免关键字:

if (sum = zv.sum(:volume).to_f) == 0.0; 1.0 else sum end
Run Code Online (Sandbox Code Playgroud)

并使用(仍然无用的)条件运算符:

(sum = zv.sum(:volume).to_f) == 0.0 ? 1.0 : sum
Run Code Online (Sandbox Code Playgroud)

如果你不介意一些稍微复杂的非本地控制流,你可以这样做:

zv.sum(:volume).to_f.tap {|sum| break 1.0 if sum == 0.0 }
Run Code Online (Sandbox Code Playgroud)

拉出浮点转换:

zv.sum(:volume).tap {|sum| break 1 if sum == 0 }.to_f
Run Code Online (Sandbox Code Playgroud)

此外,如果您知道有关总和的一些特殊情况,例如,如果您知道总和总是恰好为 0 或大于 1,那么您可以利用这些额外知识,并可能执行以下操作:

[1.0, zv.sum(:volume).to_f].max
Run Code Online (Sandbox Code Playgroud)

拉出浮点转换:

[1, zv.sum(:volume)].max.to_f
Run Code Online (Sandbox Code Playgroud)

但是,请注意,这些都不像第一个版本那样可读和清晰。

另外,请注意您问题中的描述和问题中的代码不匹配,因为代码不符合您在问题中描述的内容。


Ste*_*fan 5

您可以使用nonzero?将零视为假值:

zv.sum(:volume).to_f.nonzero? || 1.0
Run Code Online (Sandbox Code Playgroud)

或者:

(zv.sum(:volume).nonzero? || 1).to_f
Run Code Online (Sandbox Code Playgroud)

  • 我预计 90% 以上不熟悉“nonzero?”的人(包括我自己)会假设它返回“true”或“false”,从而提出了它是否是 Ruby 核心的有用补充的问题。 (3认同)