在 JavaScript 中,如何确保数组至少有一个特定元素,而其他元素满足另一个条件?

Posted

技术标签:

【中文标题】在 JavaScript 中,如何确保数组至少有一个特定元素,而其他元素满足另一个条件?【英文标题】:In JavaScript how to make sure that array has at least one specific element and the others meet another condition? 【发布时间】:2020-12-16 18:47:16 【问题描述】:

给定一个包含一些状态字符串的数组, 我想验证数组是否至少包含一个sleeping 状态,然后验证其余状态是ok 还是sleeping

所以一个有效的数组是['ok', 'sleeping', 'sleeping', 'ok'],一个无效的数组就是const states = ['ready', 'working','onBreak','sleeping', 'ok', 'sleeping']

到目前为止,我想出的是:


const validArray = ['ok', 'sleeping', 'sleeping', 'ok'];

const isvalid = validArray.some( x => x === 'sleeping')

if(isValid)
  const canDoStuff = validArray.some( x => !['ok','sleeping'].includes(x))
  if(canDoStuff)
    doStuff()  
  

理想情况下,我想在一个循环中验证这一点,而不是两个循环。

【问题讨论】:

在一个循环中执行它很奇怪。因为“如果睡眠存在”的测试一旦找到就可以终止,而“除了好的或睡眠之外的东西”的测试可能必须一直评估到最后 @Taplar 我没有看到使用单个循环有什么奇怪的地方。在最坏的情况下(所有条目都是“正常”或“睡眠”),无论如何您都必须扫描整个数组。只有遇到这两个值以外的值时,才能提前突破。无论您使用一个循环还是多个循环,情况都是如此。有关单循环解决方案的示例,请参阅 my answer。 【参考方案1】:

如果您想要最快的代码,请使用简单的for 循环:

'use strict';

function isValid( array ) 
    let sleeping = false;
    for( const item of array ) 
        if( item === 'sleeping' ) 
            sleeping = true;
         else if( item !== 'ok' ) 
            return false;
        
    
    return sleeping;


function test( array ) 
    console.log( isValid(array) ? 'Valid:' : 'Invalid:', array );


test( [ 'ok', 'sleeping', 'sleeping', 'ok' ] );
test( [ 'ready', 'working','onBreak','sleeping', 'ok', 'sleeping' ] );

这比其他答案建议的代码多一点,但它会比其中任何一个都快。

特别是,接受的答案使用两个循环,而不是一个。您不会直接看到循环,因为它们隐藏在 .includes().every() 调用中。

我并不是说这是对那段代码的批评——它非常干净和简单,我一直很喜欢。但是当性能很重要时,编写可让您将多个循环合二为一的老式代码会有所帮助。

当然,在性能可能很重要时进行基准测试总是明智的,因此我接受了@scunliffe 创建的测试(谢谢!)并添加了一个使用此 for 循环的测试:https://jsben.ch/vrzl1

如果您需要支持旧版本的 Internet Explorer,请使用数字 for 循环代替 for-of 循环,并使用 var 代替 letconst

【讨论】:

我认为简单的 for 循环具有价值并且能够完全控制其中的测试,但是我认为 OP 正在考虑如果所有条目都是有效的数组 either i> ok or sleep... 并且至少有一个值是“sleeping”。 @scunliffe 我很确定这正是这段代码的作用。如果任何项目不是 'sleeping' 并且不是 'ok',它会返回 false。如果所有项目都是“睡眠”或“正常”,则如果至少有一个项目“睡眠”,则返回 true,否则返回 false。你能指出逻辑中的错误,或者你有一个失败的测试用例吗? 你说得对,我把“!==”误读为“===”,你的代码没问题。【参考方案2】:

您可以使用如下简单的 for 循环:

const validate = arr => 
  let foundSleeping = false;
  for (let str of arr) 
    if (!["sleeping", "ok"].includes(str)) return false;
    if (str === "sleeping") foundSleeping = true;
  
  
  return foundSleeping;
;


console.log(validate(['ok', 'sleeping', 'sleeping', 'ok']));
console.log(validate(['ready', 'working','onBreak','sleeping', 'ok', 'sleeping']));

【讨论】:

【参考方案3】:

而不是.some 来检查是否有一个sleeping 项目,使用.includes

但是,您的另一个 .some 也没有实现正确的逻辑; doStuff 只会在至少有一项匹配的情况下运行。请改用.every,并检查每个是否匹配:

const validate = input => (
  input.includes('sleeping') &&
  input.every(x => ['ok', 'sleeping'].includes(x))
);

console.log(validate(['ok', 'sleeping', 'sleeping', 'ok']));
console.log(validate(['ready', 'working','onBreak','sleeping', 'ok', 'sleeping']));

【讨论】:

主要是为了咯咯笑...但是我尝试在每次检查之前/之后使用不同的数组内容测试包含检查的性能...有趣的是,不同的浏览器会找到一种或另一种表现更好的方法jsben.ch/8IwR1 - 我的一般想法是,如果您希望能够尽早退出,请先测试 every(),然后尝试包含但 YMMV。 @sgunliffe 感谢您创建了这个有趣的测试套件。不过,每种情况的性能都由console.log 调用决定。我在 jsben.ch/vrzl1 添加了一个新版本的测试,它删除了这些调用,并从我的答案中添加了 for 循环代码。不管有没有console.log,我确实注意到在同一个浏览器中从一次运行到另一次运行有相当多的变化。有时“包含优先”更快,有时“每个第一个”更快。在所有情况下,for 循环都比任何一个都快。

以上是关于在 JavaScript 中,如何确保数组至少有一个特定元素,而其他元素满足另一个条件?的主要内容,如果未能解决你的问题,请参考以下文章

查找数组中是不是至少有一次从 1 到 K 的所有数字

在 Auto Scaling 组中,确保在给定的可用区中至少有一个 ec2 实例始终可用

请确保至少有一个领域可以验证这些令牌

如何修复“在解释器中至少有 1 个以 numpy 数组或切片的形式引用的内部数据”并在 tf.lite 上运行推理

用HTML和JavaScript代码编写一个至少有3个框架的网页:

MS-Access 2007:查询与至少有一条记录符合指定条件的个人相关的所有记录