【问题标题】:Check exactly one boolean option set准确检查一个布尔选项集
【发布时间】:2013-06-26 02:38:06
【问题描述】:

嗯,这有点骇人听闻:

function b2n(boo) {
    return boo ? 1 : 0;
}

if(b2n(opt1) + b2n(opt2) + b2n(opt3) !== 1) {
    throw new Error("Exactly one option must be set");
}

有没有更好的方法在 Javascript 中做到这一点?使用任何一个

  • 更智能的布尔/数字处理
  • 偷偷摸摸的数组或函数操作

等等。欢迎使用 Javascript 和 Node 解决方案。

在我的实际问题中,选项来自 Node 模块指挥官,所以我不是在处理真正的布尔值,而是真实和虚假的事情。也可能有指挥官解决方案。

【问题讨论】:

  • 您要解决的用例是什么?你在验证用户输入吗?如果是这样,您可以使用单选按钮吗?
  • @ChadCook 这是服务器端。由node.js指挥官指挥。在我的实际问题中,它默认为opt3,所以我实际上检查了> 1
  • 你是如何在服务器端运行 Javascript 的?
  • (真 + 假 === 1)。 Boolean 将自动转换为 int
  • @DmitryTeplyakov 是的,需要使用 !! 确保值也是布尔值。

标签: javascript node.js


【解决方案1】:

假设您有一系列选项,您可以这样做:

if(opts.filter(Boolean).length !== 1) {}

在我看来,你应该有一个具有三种可能状态的变量...

var opt = 'a'; // (or 'b', or 'c')

【讨论】:

  • 为什么还要麻烦传递一个匿名函数?只需使用if (opts.filter(Boolean).length !== 1) {}。或者即使使用您的匿名函数,只返回 v 更有意义
  • 感谢您建议只使用布尔函数。没想到,这是一个很大的进步。至于只是返回 v,我最初是这样编码的,但由于提问者不确定这些值首先是否实际上是布尔值而改变了它。
  • 没问题!是的,如果它像这样简单,我会尝试想办法传递内置函数而不是自定义函数。对于返回v,它可以工作——从传递给filter 的回调返回的值被评估为truthy,而不是true,因此内容是否为布尔值并不重要。例如,如果你只是return v;"" 不会通过,而"a" 会。使用Boolean 在技术上做同样的事情,只是更快
  • 太棒了,@spudly!我希望我能想到这一点。
【解决方案2】:

你可以这样做:

if ( !!opt1 + !!opt2 + !!opt3 !== 1 ) {

之所以有效,是因为

  • !! 从任何值生成一个布尔值(true,如果对象在 if(value) 中计算为 true
  • 添加布尔值时,true1false0

【讨论】:

  • 如果他知道它们是布尔值,那么 !!是不必要的,因此您可以将其更改为 if (opt1 + opt2 + opt3 != 1) {}
  • @spudly 我不知道这些值是否为布尔值。问题中并不清楚。
  • 它们实际上不是,无论如何这是最安全的方法。
  • 可读性较差,但您可以将表达式简化为:!opt1 + !opt2 + !opt3 === 2(2 是选项数,3 减去一个真实选项)。
  • @Paulpro 是的,这是真的,但我认为这不值得。在我看来,与目标的语义差距太大了。
【解决方案3】:

您在评论中提到这是来自指挥官选项对象。

您可以使用Lodash 更优雅地做到这一点:

if (_(options).values().compact().size() === 1)

如果只想统计选项的子集,可以插入

.pick('a', 'b', 'c')

【讨论】:

  • 啊,这就是你流利使用lodash的方式。
【解决方案4】:
if ([opt1, opt2, opt3].reduce(function(x, y) { return x + !!y }, 0) == 1) {
    // exactly one
};

ECMAScript 5 reduce 函数。

【讨论】:

    【解决方案5】:

    我觉得你太聪明了,怎么了:

    var optionsSelected = 0;
    if( opt1 ) optionsSelected++;
    if( opt2 ) optionsSelected++;
    if( opt3 ) optionsSelected++;
    
    if( optionsSelected !== 1 ) {
        throw new Error("Exactly one option must be set");
    }
    

    当然我也可以玩聪明的游戏:

     if( opts.filter(Boolean).length !== 1 ) {
         throw new Error("Exactly one option must be set");
     }
    

    【讨论】:

    • Javascript 有很多被广泛接受的模式,可以让你在可读的一行代码中完成需要 8 行的代码。我更喜欢“聪明”的模式,因为它们被充分理解(因此不是聪明的)。我是 Javascript 的新手,所以还不知道这些。
    • 有关“聪明”解决方案的示例,请参阅其他答案。
    • 早该给聪明的,人都是善变的。
    【解决方案6】:

    @spudly 走在正确的轨道上,但它可能会更紧凑一点:

    if( [opt1,opt2,opt3].filter(function(x){return x}).length!==1 ) {
        throw new Error("Exactly one option must be set");
    }
    

    更多信息请参见ES5's filter method

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-05
      • 2019-04-27
      • 1970-01-01
      • 2013-07-22
      相关资源
      最近更新 更多