3

Is there a smart way to find out if there are at least two values greater than 0 in an array and return true? And false in the opposite case?
(hypothetical and wrong example using some):

const a = [9, 1, 0];
const b = [0, 0, 0];
const c = [5, 0, 0];

const cond = (el) => el > 0 && somethingElseMaybe;

console.log(a.some(cond)); // print true
console.log(b.some(cond)); // print false
console.log(c.some(cond)); // print false


Memmo
  • 298
  • 3
  • 8
  • 31
  • 2
    you mean, other than iterating through the array until you get 2 values > 0 - or sorting the array in decreasing order and check the first two element? – Jaromanda X Feb 17 '20 at 13:11
  • Please either define "fast and elegant" or remove it altogether. – Heretic Monkey Feb 17 '20 at 13:11
  • 1
    `array.filter(x => x > 0).length >= 2;` (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) – Ryan Wilson Feb 17 '20 at 13:12
  • 1
    Most often, "performant" and "elegant" are mutual exclusive. An elegant solution (less code) is slow and memory consuming, a performant solution (a lot of ugly code) is fast an less memory-consuming. Pick the latter, if the arrays are really big, pick the former, if there really are only three members in the array, and not too many arrays to handle. – Teemu Feb 17 '20 at 13:20
  • no, there is no elegance in this kind of coding problem – Mister Jojo Feb 17 '20 at 13:21

6 Answers6

8

Use filter() to remove values below zero and then check if the length of resulting array is greater than or equal to two

const twoGreaterThanZero = arr => arr.filter(x => x > 0).length >= 2;

console.log(twoGreaterThanZero([9, 1, 0])) //true
console.log(twoGreaterThanZero([0, 0, 0])) //false
console.log(twoGreaterThanZero([5, 0, 0])) //false
Maheer Ali
  • 35,834
  • 5
  • 42
  • 73
  • Good answer, same as what I put in the comments. Not sure why someone down-voted. But then again most times you never do. +1. – Ryan Wilson Feb 17 '20 at 13:14
  • 1
    Downvoter please comment and point out if there is any mistake in the answer? – Maheer Ali Feb 17 '20 at 13:15
  • use dynamic values instead of hard integer array values. – Harsimranjit Singh Feb 17 '20 at 13:21
  • 2
    @MaheerAli I'd guess the downvote is because this will iterate the whole array even if you'd find the answer in the beginning. Not that it would matter in most cases. – Alex Feb 17 '20 at 13:36
  • I downvoted for the above reason. – Ben Aston Feb 17 '20 at 14:13
  • @Ben I don't mind it. But OP said "Is there an **easy to read** and elegant way".OP didn't asked for a code with more performance. So it doesn't make any sense to over complicate the code without need. – Maheer Ali Feb 17 '20 at 14:57
  • Sure. Yours is a valid answer. Personally, I don't think the solution that avoids the need - in most cases - to scan the entire array is much more complicated, however. – Ben Aston Feb 17 '20 at 15:00
  • I think that this is a totally correct solution to the OP question. He did not mention the "type" or size of the array, neither if it is in any way dynamic. Assuming that every code has to deal with big data or similar is in my opinion limiting the scope of programming. Although being "performance aware" is a good quality, it is much better for it to be context dependent on each situation and project. – user3658510 Aug 20 '21 at 01:48
5

To avoid wasted effort, you should stop the checking as soon as the condition is met. I think this meets your requirement.

function twoGreaterThanZero(arr) { 
    let counter = 0
    for(let x of arr) {
        if(x > 0 && (++counter > 1)) return true
    }
    return false
}

const a = [9, 1, 0]
const b = [0, 0, 0]
const c = [5, 0, 0]

console.log(twoGreaterThanZero(a)) // print true
console.log(twoGreaterThanZero(b)) // print false
console.log(twoGreaterThanZero(c)) // print false
Ben Aston
  • 53,718
  • 65
  • 205
  • 331
2

If you don't want to iterate over the entire array you can use a loop and break out of it early once your condition is satisfied. I think the answer that uses filter is more elegant, but if you're list is insanely large you might see a benefit from not iterating the entire thing.

I broke this function into it's basic parts and created a curried version.

The question is "are there 2 or more values greater than 0 in the array". But it can be boiled down to "are there X or more values that pass comparator"?

const a = [9, 1, 0];
const b = [0, 0, 0];
const c = [5, 0, 0];

const quantityCompare = compare => quantity => arr => {
  let count = 0;
  for (let i = 0; i < arr.length; i += 1) {
    if (compare(arr[i])) count += 1;
    if (count >= quantity) return true;
  }
  return false;
};

const twoElementsGreaterThanZero = quantityCompare(x => x > 0)(2);

console.log(twoElementsGreaterThanZero(a)); // true
console.log(twoElementsGreaterThanZero(b)); // false
console.log(twoElementsGreaterThanZero(c)); // false

One more for fun, you can use Array.some (an Array.forEach you can break out of) instead of the for loop:

const a = [9, 1, 0];
const b = [0, 0, 0];
const c = [5, 0, 0];

const quantityCompare = compare => quantity => arr => {
  let count = 0;
  return arr.some(el => {
    if (compare(el)) count += 1;
    if (count >= quantity) return true;
  })
}

const twoElementsGreaterThanZero = quantityCompare(x => x > 0)(2);

console.log(twoElementsGreaterThanZero(a)); // true
console.log(twoElementsGreaterThanZero(b)); // false
console.log(twoElementsGreaterThanZero(c)); // false
Jon Church
  • 2,320
  • 13
  • 23
  • Using `some` is a neat hack, but I think I'd be surprised to see it used this way in a production codebase. – Ben Aston Feb 17 '20 at 14:24
  • 1
    I agree, I included it because I found it neat as well. I don't think using `some` improves anything here, and in fact makes things less straight forward since it's not a very common array function imo. – Jon Church Feb 17 '20 at 14:33
1

If you are in a situation where doing things like this is frequently necessary, you can always create your own facility for producing predicate functions. In this case, you could start with a master function to create functions that return true or false if an array contains a minimum number of values that satisfy a condition:

function minimumSatisfy(condition, minimum) {
  return function(array) {
    for (var i = 0, c = 0; i < array.length && c < minimum; i++) {
      if (condition(array[i]))
        c++;
    }
    return c >= minimum;
  }
}

To use that for checking your particular case, use it to make a specific function:

let twoGtZero = minimumSatisfy(v => v > 0, 2);

Now you can test any array with that predicate:

if (twoGtZero(someArray)) {
  // ...
}

Of course if you've only got one place in your code that requires such a test, it would be silly to do this.

Pointy
  • 405,095
  • 59
  • 585
  • 614
0

Try that

var a = [9, 1, 0]
var b = [0, 0, 0]
var c = [5, 0, 0]

function atLeastTwoEntries(arr, entrie) {
  return arr.indexOf(entrie) !== arr.lastIndexOf(entrie)
}

console.log(atLeastTwoEntries(a, 0))
console.log(atLeastTwoEntries(b, 0))
console.log(atLeastTwoEntries(c, 0))
-1

Try this,

console.log(a.filter(s => s > 0).length >= 2); // print true
console.log(b.filter(s => s > 0).length >= 2); // print false
console.log(c.filter(s => s > 0).length >= 2); // print false