Skip to content
Advertisement

Javascript filtering a nested array to exclude objects that don’t include one of several elements

I have a fairly simple nested array of objects. Each object is composed of 5 (string) values, e.g. [“0,0”, “0,0”, “0,0”, “0,0”, “0,1”]. There are no variables attached, hence using arrays inside an array.

Each object represents a puzzle solve permutation being tested by other parts my code. The main data set is composed of 150k permutations.

let haystack = [
["1,0", "0,0", "0,0", "0,0", "0,0"],
["0,0", "0,2", "0,0", "0,0", "0,1"],
["2,2", "0,0", "4,2", "0,2", "1,1"],
["0,0", "0,0", "3,0", "0,0", "2,1"],
["0,0", "0,0", "0,0", "0,0", "2,2"],
["0,0", "0,2", "0,0", "0,0", "3,2"],
["0,0", "0,0", "0,1", "0,0", "0,3"],
["0,0", "0,1", "0,0", "1,0", "3,0"],
["0,1", "0,0", "4,2", "1,0", "2,1"],
["0,3", "0,0", "0,1", "0,0", "3,2"],
["0,0", "3,2", "0,0", "1,0", "0,2"],
["0,0", "1,0", "0,0", "1,0", "4,2"],
["0,0", "0,0", "0,0", "1,0", "2,2"],
["0,0", "0,0", "0,0", "1,0", "3,2"],
["0,2", "3,2", "0,1", "1,0", "0,1"]]

I want to filter this ‘haystack’, but each object in the array must pass 3 filters (needle1, needle2, needle3):

let needle1 = haystacks[i].includes("0,1" || "3,0" || "3,2" || "4,2");
let needle2 = haystacks[i].includes("1,0" || "2,0" || "1,2" || "2,2");
let needle3 = haystacks[i].includes("0,0" || "3,2");

If it fails any single filter, it should not carry over to the new array.

So this line:

["0,0", "0,0", "0,0", "0,0", "2,2"],

would pass the needle3 filter, but not the needle1 filter.

The new array would include only those objects in the old array that pass all three tests.

newHaystack = [
["2,2", "0,0", "4,2", "0,2", "1,1"],
["0,0", "0,1", "0,0", "1,0", "3,0"],
["0,1", "0,0", "4,2", "1,0", "2,1"],
["0,0", "3,2", "0,0", "1,0", "0,2"],
["0,0", "1,0", "0,0", "1,0", "4,2"],
["0,0", "0,0", "0,0", "1,0", "3,2"],
["0,2", "3,2", "0,1", "1,0", "0,1"]];

I have found code that would filter for any of a number of elements present, regardless of position:

let needle1 = ["4,2", "0,0", "2,1"];

const haystack2 = haystack.filter(item =>
    needle1.every(val => item.indexOf(val) > -1));

would return:

[ [ “0,1”, “0,0”, “4,2”, “1,0”, “2,1” ] ]

but it isn’t exactly what I’m looking for. I want ‘this’ or ‘this’ or ‘this’, rather than ‘this’ & ‘this’ & ‘this’.

In other parts of my code, I worked through the array with something like this:

let needle1 = haystacks[i].includes("0,1" || "3,0" || "3,2" || "4,2");

and then in the main loop, I simply skipped past the object with something like.

if (needle1 !== true) {skipObject(); return;}
if (needle2 !== true) {skipObject(); return;}
if (needle3 !== true) {skipObject(); return;}

But the javascript file is currently over the 10MB limit with such a big dataset of permutations, and my goal is to thin the array of permutations I know don’t work.

Any hints as to a solution would be useful.

Tested this suggestion from @Ethan_Snow, but it’s outputting 15 objects to the array instead of 7.

let needle1 = ["0,1", "3,0", "3,2", "4,2"];
let needle2 = ["1,0", "2,0", "1,2", "2,2"];
let needle3 = ["0,0", "3,2"];
let needles = [needle1, needle2, needle3];
const haystack2 = haystack.filter(stack => {
    return needles.every(needles => {return needles.some(item => stack.includes(item) > -1)
    })
})
console.log(haystack2);

Advertisement

Answer

If im understanding your question correctly, you Can use filter and Array.some, and check that it satisfies every needle

let needle1 = ["0,1", "3,0", "3,2",  "4,2"];
let needle2 = ["1,0", "2,0", "1,2", "2,2"];
let needle3 = ["0,0", "3,2"];
let needles = [needle1, needle2, needle3]
const haystack2 = haystack.filter(stack => {
    return needles.every(needle => {
        return needle.some(item => stack.includes(item)
    }); 
})

console.log(haystack2);

This should check that atleast One item from each “needle” in needles is in the stack, and filters out stacks that dont meet all three

Advertisement