Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In JavaScript how to make sure that array has at least one specific element and the others meet another condition?

Given an array that contains some status string, I want to validate if the array contains at least one sleeping status and then validate if the rest of the statuses are either ok or sleeping.

So a valid array is ['ok', 'sleeping', 'sleeping', 'ok'] and an invalid array will be something like const states = ['ready', 'working','onBreak','sleeping', 'ok', 'sleeping']

What I have come up with so far is this:


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()  
  }
}

Ideally, I would like to validate that in a single loop,and not two loops.

like image 439
Second Son Avatar asked Oct 29 '25 08:10

Second Son


2 Answers

Rather than .some to check if there's one sleeping item, use .includes.

But, your other .some isn't implementing the right logic either; doStuff will only run if there's at least one item which doesn't match. Use .every instead, and check that each does match:

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']));
like image 62
CertainPerformance Avatar answered Oct 30 '25 23:10

CertainPerformance


If you want the fastest code, use a simple for loop:

'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' ] );

This is a bit more code than the other answers suggest, but it will be faster than any of them.

In particular, the accepted answer uses two loops, not one. You don't see the loops directly because they are hidden inside the .includes() and .every() calls.

I don't mean this as a criticism of that code - it is very clean and simple, which I always like. But when performance counts, it can help to write old-school code that lets you combine multiple loops into one.

Of course it is always wise to benchmark when performance may matter, so I took the test that @scunliffe created (thanks!) and added a test that uses this for loop: https://jsben.ch/vrzl1

If you need to support old versions of Internet Explorer, use a numeric for loop instead of the for-of loop, and var instead of let and const.

like image 44
Michael Geary Avatar answered Oct 31 '25 00:10

Michael Geary



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!