1

I have the following array of objects:

let a = [
    {
        b: [1, 11, 12],
        c: "a1"
    },
    {
        b: [2, 56, 1],
        c: "a2"
    },
    {
        b: [1, 2, 3],
        c: "a3"
    }
]

I want to do the simplest operation where I can return a second array that is a copy of a but includes only the elements whose b array contains at least one element greater than 10, and for each such element, have b contain only the element(s) greater than 10. So I want the output to be:

[
    {
        b: [11, 12],
        c: "a1"
    },
    {
        b: [56],
        c: "a2"
    }
]

I know I could do this naively with loops or in multiple steps using filter(), but I'm wondering if there's an efficient one-line solution. Any tips?

3
  • 1
    Just to confirm, by "efficient" you mean as little code as possible? Commented Feb 1, 2019 at 18:22
  • You can do it in one line with .filter Commented Feb 1, 2019 at 18:22
  • As with any filter operation, the most efficient way will be O(n). How you get there doesn't really matter. Commented Feb 1, 2019 at 22:11

8 Answers 8

3

You can use filter and reduce like this:

let a = [{b:[1,11,12],c:"a1"},{b:[2,56,1],c:"a2"},{b:[1,2,3],c:"a3"}]

const output = a.reduce((acc, { b, c }) => {
  // filter "b" property
  const filtered = b.filter(n => n > 10);
  
  if (filtered.length)
    acc.push({ b: filtered, c });
    
  return acc;
}, [])

console.log(output)

Sign up to request clarification or add additional context in comments.

Comments

3

You can use .filter() and .map() to get the desired output:

let a = [{
    b: [1, 11, 12],
    c: "a1"
}, {
    b: [2, 56, 1],
    c: "a2"
}, {
    b: [1, 2, 3],
    c: "a3"
}];

let b = a.filter(({ b }) => b.some(v => v > 10))
         .map(o => Object.assign({}, o, {b: o.b.filter(v => v > 10)}));

console.log(b);
.as-console-wrapper {max-height: 100% !important; top: 0; }

1 Comment

Sorry, I actually misread the requirement here. And you're right. I'm not even sure why you'd want to do this on one line - seems like hell to maintain when you next need to change anything.
1

You can use reduce and filter

let a = [{b: [1, 11, 12],c: "a1"},{b: [2, 56, 1],c: "a2"},{b: [1, 2, 3],c: "a3"}]


let op = a.reduce((out,{b,c})=>{
  let temp = b.filter(e => e > 10);
  if(temp.length){
    out.push( { b : temp,c })
  } 
  return out
},[])

console.log(op)

Comments

1

Here is a simple way too do this.

let a = [
    {
        b: [1, 11, 12],
        c: "a1"
    },
    {
        b: [2, 56, 1],
        c: "a2"
    },
    {
        b: [1, 2, 3],
        c: "a3"
    }
]

var result = [];
a.forEach((item) => {
var subItem = { c:item.c, b: item.b.filter((b)=> b > 10)}
if (subItem.b.length>0)
     result.push(subItem);
});

console.log(result)

Comments

1
let result = a.map((rec)=> {rec.b.filter((bRec)=>bRec>10), rec.c}).filter((rec)=>rec.b.length == 0);

Comments

1

Other great answers here. My take is :

var ans = a.slice().filter(item => {
    item.b = item.b.filter(s => s > 10)
  return (item.b.length > 0) ? true : false;
})

Comments

0

UPDATE There are a bunch of great answers on here (I upvoted all so far). Here's what I eventually came up with though:

a.filter(x => x.b.some(y => y>10)).map((z) => {
    return {
        b: z.b.filter(zb => zb>10),
        c: z.c
    }
})

Explanation:

You take 'a', and filter it down to include only those elements for which 'b' has 'some element y such that y>10'. So at this point you would have filtered out the third element of 'a' since it does not have any elements in it's 'b' that are > 10. You now have this:

[
    {
        b: [1, 11, 12],
        c: "a1"
    },
    {
        b: [2, 56, 1],
        c: "a2"
    }
]

Next you map that new array, ie. for each element you return a new element in a new array that has the same value of 'c', and the same value of 'b' except filtered to include only those elements that are > 10. Thus you end up with:

[
    {
        b: [11, 12],
        c: "a1"
    },
    {
        b: [56],
        c: "a2"
    }
]

Thanks for all your contributions!

Comments

0

Since no one mentioned it, here is one approach using nested filters().

I based this approach in the condition that if the b array have some element greater than 10, then the result of filtering it by the previous condition will give as result a non-empty array.

Also note, this do not mutate the original array, because it changes the copy of the array that filters receive.

let a = [
    {b: [1, 11, 12], c: "a1"},
    {b: [2, 56, 1], c: "a2"},
    {b: [1, 2, 3], c: "a3"}
]

let res = a.filter(
    ({b}, i, arr) => (arr[i].b = b.filter(x => x > 10)) && arr[i].b.length > 0
);

console.log(res);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.