根据值列表检查变量是不是相等

Posted

技术标签:

【中文标题】根据值列表检查变量是不是相等【英文标题】:Check variable equality against a list of values根据值列表检查变量是否相等 【发布时间】:2011-01-18 19:27:15 【问题描述】:

我正在检查一个变量,比如foo,是否与多个值相等。例如,

if( foo == 1 || foo == 3 || foo == 12 ) 
    // ...

关键是对于这样一个微不足道的任务,它的代码相当多。我想出了以下几点:

if( foo in 1: 1, 3: 1, 12: 1 ) 
    // ...

但这并不完全吸引我,因为我必须为对象中的项目赋予冗余值。

有人知道对多个值进行相等性检查的体面方法吗?

【问题讨论】:

我认为在决定这样的事情时需要考虑更大的背景,因为了解为什么进行此类比较非常重要。 好吧,在我正在创建的游戏中,我正在检查键盘代码以确定应该调用什么函数。在不同的浏览器中,一个键看起来有不同的键码,因此需要与多个值进行比较。 检查多个方法的性能测试,逻辑运算符获胜runkit.com/pramendra/58cad911146c1c00147f8d8d 这是一个常见的重复目标,用于询问为什么variable === value1 || value2 不起作用。对于那些想知道为什么的人:||&& 与 short-circuit evaluation 一起使用;每个操作数要么是truthy or falsy。 x === 1 || 2 表示 (x === 1) || (2) 并且是 true2,因为 || 导致第一个真值或最后一个假值操作数,而 x === "a" || "b"true"b"。由于true2"b" 都是真值,因此将它们置于if 条件中等效于if(true)。只需使用[ "a", "b" ].includes(x) 【参考方案1】:

你可以使用数组和indexOf:

if ([1,3,12].indexOf(foo) > -1)

【讨论】:

我喜欢这个。我猜甚至可以通过原型创建一个“包含”函数,从而消除 > -1 的使用。 @pimvdb:请注意,您可能需要自己的实现,因为 indexOf 仅在 ECMAScript 第 5 版之后才可用。 '>' 是否比 '!==' 更好? 你可以用~操作符代替> -1:if ( ~[...].indexOf(foo) ) ... @MaxWaterman 首先,绝对没有必要检查结果的类型,因为indexOf 总是返回一个数字,所以!= 就足够了。而且> 更短,所以是的,它更好【参考方案2】:

在 ECMA2016 中,您可以使用 includes 方法。这是我见过的最干净的方式。 (所有主流浏览器都支持)

if([1,3,12].includes(foo)) 
    // ...

【讨论】:

对于变量if([a,b,c].includes(foo)) 或字符串if(['a','b','c'].includes(foo)) for variables => if([a,b,c].includes(foo)) 因为引号将使其成为字符串。 @HastigZusammenstellen @BinodShrestha 我想这就是我写的,除非我遗漏了什么。 “对于变量……或字符串……”【参考方案3】:

使用提供的答案,我得到了以下结果:

Object.prototype.in = function() 
    for(var i=0; i<arguments.length; i++)
       if(arguments[i] == this) return true;
    return false;

可以这样称呼:

if(foo.in(1, 3, 12)) 
    // ...


编辑:我最近遇到了这个“技巧”,如果值是字符串并且不包含特殊字符,这很有用。对于特殊字符,由于转义而变得丑陋,也因此更容易出错。

/foo|bar|something/.test(str);

更准确地说,这将检查确切的字符串,但对于简单的相等性测试来说又是更复杂的:

/^(foo|bar|something)$/.test(str);

【讨论】:

天哪!我很惊讶它的工作原理——injavascript 中的一个关键字。例如,运行function in() ; in() 会导致语法错误,至少在 Firefox 中是这样,我不确定为什么您的代码不会。 :-) 此外,扩展Object.prototype 通常被认为是不好的做法,因为它会以不幸的方式影响for (foo in bar)。也许将其更改为 function contains(obj) for (var i = 1; i &lt; arguments.length; i++) if (arguments[i] === obj) return true; return false; 并将对象作为参数传递? 扩展 Object.prototype 是一种反模式,不应使用。请改用函数。 如上所述扩展Object.prototype 这种方式有严重的缺点,可能会导致许多错误。如果你确实想扩展Object.prototype,请始终通过Object.defineProperty 进行扩展,而无需在描述符中设置enumerable @BenBlank - 仅供参考,使用关键字作为文字属性名称在第 5 版规范(2009 年 12 月)中变得有效,这就是 x.in() 起作用的原因。在第 5 版之前,您必须使用计算属性名称 (x["in"]())。【参考方案4】:

现在您可能有更好的解决方案来解决这种情况,但我更喜欢其他方式。

const arr = [1,3,12]
if( arr.includes(foo))  // it will return true if you `foo` is one of array values else false
  // code here    

我更喜欢上面的解决方案,而不是 indexOf 检查您还需要检查索引的地方。

includes docs

if ( arr.indexOf( foo ) !== -1 )  

【讨论】:

【参考方案5】:

这很容易扩展和阅读:

switch (foo) 
    case 1:
    case 3:
    case 12:
        // ...
        break

    case 4:
    case 5:
    case 6:
        // something else
        break

但不一定更容易:)

【讨论】:

我实际上使用了这种方法,因为我想在每个值旁边放一个注释来描述值相关的内容,这是实现它的最易读的方式。 @pholcroft 如果您需要描述每个值与您相关的内容,您应该创建一个枚举或类,并将您的属性编写为具有描述性的名称。【参考方案6】:

如果您将L 定义为,则可以编写if(foo in L(10,20,30))

var L = function()

    var obj = ;
    for(var i=0; i<arguments.length; i++)
        obj[arguments[i]] = null;

    return obj;
;

【讨论】:

我认为说原型函数也在数组/对象中是谨慎的 - 所以如果数组/对象的原型中有一个函数 'remove' ,它将总是返回 true 如果你编码'remove' in L(1, 3, 12),虽然你没有指定'remove'被放入列表中。【参考方案7】:
var a = [1,2,3];

if ( a.indexOf( 1 ) !== -1 )  

请注意,indexOf 不在核心 ECMAScript 中。您需要为 IE 和其他不支持 Array.prototype.indexOf 的浏览器提供 sn-p。

if (!Array.prototype.indexOf)

  Array.prototype.indexOf = function(searchElement /*, fromIndex */)
  
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (len === 0)
      return -1;

    var n = 0;
    if (arguments.length > 0)
    
      n = Number(arguments[1]);
      if (n !== n)
        n = 0;
      else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
        n = (n > 0 || -1) * Math.floor(Math.abs(n));
    

    if (n >= len)
      return -1;

    var k = n >= 0
          ? n
          : Math.max(len - Math.abs(n), 0);

    for (; k < len; k++)
    
      if (k in t && t[k] === searchElement)
        return k;
    
    return -1;
  ;

【讨论】:

直接是Mozilla的copy。懒得链接了。 developer.mozilla.org/en/JavaScript/Reference/Global_Objects/… 如果您实际上没有移位位,那么在定义 len 时是否存在位移位的原因?这里有什么隐含的强制吗? “请注意,indexOf 不在核心 ECMAScript 中。” 它是在 2009 年 12 月的第 5 版规范中添加的。【参考方案8】:

此外,由于您检查结果所依据的值都是唯一的,您也可以使用Set.prototype.has()。

var valid = [1, 3, 12];
var goodFoo = 3;
var badFoo = 55;

// Test
console.log( new Set(valid).has(goodFoo) );
console.log( new Set(valid).has(badFoo) );

【讨论】:

【参考方案9】:

我喜欢接受的答案,但认为让它也能接受数组会很整洁,所以我将其扩展为:

Object.prototype.isin = function() 
    for(var i = arguments.length; i--;) 
        var a = arguments[i];
        if(a.constructor === Array) 
            for(var j = a.length; j--;)
                if(a[j] == this) return true;
        
        else if(a == this) return true;
    
    return false;


var lucky = 7,
    more = [7, 11, 42];
lucky.isin(2, 3, 5, 8, more) //true

您可以通过将== 更改为=== 来移除类型强制。

【讨论】:

【参考方案10】:

如果您有权访问下划线,则可以使用以下内容:

if (_.contains([1, 3, 12], foo)) 
  // ...

contains 以前也可以在 Lodash 中工作(在 V4 之前),现在你必须使用 includes

if (_.includes([1, 3, 12], foo)) 
  handleYellowFruit();

【讨论】:

【参考方案11】:

我只是使用 jQuery inArray 函数和一个值数组来完成此操作:

myArr = ["A", "B", "C", "C-"];

var test = $.inArray("C", myArr)  
// returns index of 2 returns -1 if not in array

if(test >= 0) // true

【讨论】:

【参考方案12】:

这是一个小辅助箭头函数:

const letters = ['A', 'B', 'C', 'D'];

function checkInList(arr, val) 
  return arr.some(arrVal => val === arrVal);


checkInList(letters, 'E');   // false
checkInList(letters, 'A');   // true

More info here...

【讨论】:

非常好的方法:从您的想法开始,您也可以在没有辅助函数的情况下完成:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].some(option =&gt; option === valToCheck); // false 但是一旦我开始调整代码,我发现includes 成为更好的选择,正如@alister 的回答:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].includes(valToCheck); // false【参考方案13】:

对于您经常比较的较大值列表,首先构造一个Set 并使用Set#has 进行恒定时间检查可能比Array#includes 以线性时间运行更为理想。

const values = new Set([1, 2, 12]);
if(values.has(foo))
   // do something

【讨论】:

【参考方案14】:

使用 ES6 语法你可以做到:

Object.prototype.in = function (...args) 
  return args.includes(this.valueOf());

顺便也检查深度相等。需要 valueOf() 方法,因为 this 是一个对象。

【讨论】:

【参考方案15】:

对于后代,您可能希望使用正则表达式作为替代方案。浏览器支持也很好(参考https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match#Browser_compatibility)

试试这个

if (foo.toString().match(/^(1|3|12)$/)) 
    document.write('Regex me IN<br>');
 else 
    document.write('Regex me OUT<br>');

【讨论】:

以上是关于根据值列表检查变量是不是相等的主要内容,如果未能解决你的问题,请参考以下文章

如何在一个循环中比较两个列表的值是不是相等?

检查两个无序列表是不是相等[重复]

使用 pandas 根据条件将 csv 值附加到列表

检查变量是不是在临时值列表中

Python比较字典形式的列表是不是部分相等

python - 如何在python中使用IF语句检查两个列表的元素是不是相等?