Home > OS >  Filter array of objects by array attribute's attribute
Filter array of objects by array attribute's attribute

Time:04-01

I have an array like this:

const array = [
    { id: 1, name: 'a1', props: [
        { name: 'b1', typeId: 1 },
        { name: 'b2', typeId: 1 },
        { name: 'b3', typeId: 5 },
        { name: 'b4', typeId: 5 },
    ] },
    { id: 2, name: 'a2', props: [
        { name: 'c1', typeId: 1 },
        { name: 'c2', typeId: 1 },
        { name: 'c3', typeId: 5 },
    ] },
    { id: 3, name: 'a3', props: [
        { name: 'd1', typeId: 5 },
        { name: 'd2', typeId: 5 },
    ] },
    { id: 4, name: 'a4', props: [
        { name: 'e1', typeId: 1 },
    ] }
];

I want to filter this array by prop's typeId attribute. For ex:

If typeId == 5, then it should return items that ids are 1, 2, 3 with only props' typeId equals 5. Like this:

filteredArray = [
    { id: 1, name: 'a1', props: [
        { name: 'b3', typeId: 5 },
        { name: 'b4', typeId: 5 },
    ] },
    { id: 2, name: 'a2', props: [
        { name: 'c3', typeId: 5 },
    ] },
    { id: 3, name: 'a3', props: [
        { name: 'd1', typeId: 5 },
        { name: 'd2', typeId: 5 },
    ] }
];

Or if typeId == 1, then it should return items that ids are 1, 2, 4 with only props which typeId equals to 1. Like this:

    filteredArray = [
    { id: 1, name: 'a1', props: [
        { name: 'b1', typeId: 1 },
        { name: 'b2', typeId: 1 },
    ] },
    { id: 2, name: 'a2', props: [
        { name: 'c1', typeId: 1 },
        { name: 'c2', typeId: 1 },
    ] },
    { id: 4, name: 'a4', props: [
        { name: 'e1', typeId: 1 },
    ] }
];

I wrote something like this, but it doesn't work as intended. It doesn't filter props arrays. Returns an item if it's props array have an item which typeId equals to typeId.

let typeId = 1;

let filteredArray = array.filter(x => {
  return x.props.some(y => {
    return y.typeId == typeId;
  });
});

CodePudding user response:

If you don't mind modifying the input data, you can do it with a forEach :

array.forEach(
  (elt) => elt.props = elt.props.filter((subElt) => subElt.typeId === 5)
)

Also, you might want to filter elements that have elt.props empty :

const result = array.filter(elt => elt.props.length > 0)

CodePudding user response:

You can use map and filter by checking the typeId of the props

const array = [{
    id: 1,
    name: 'a1',
    props: [{
        name: 'b1',
        typeId: 1
      },
      {
        name: 'b2',
        typeId: 1
      },
      {
        name: 'b3',
        typeId: 5
      },
      {
        name: 'b4',
        typeId: 5
      },
    ]
  },
  {
    id: 2,
    name: 'a2',
    props: [{
        name: 'c1',
        typeId: 1
      },
      {
        name: 'c2',
        typeId: 1
      },
      {
        name: 'c3',
        typeId: 5
      },
    ]
  },
  {
    id: 3,
    name: 'a3',
    props: [{
        name: 'd1',
        typeId: 5
      },
      {
        name: 'd2',
        typeId: 5
      },
    ]
  },
  {
    id: 4,
    name: 'a4',
    props: [{
      name: 'e1',
      typeId: 1
    }]
  }
];

const typeId = 5;

const result = array.map(({
  id,
  name,
  props
}) => ({
  id,
  name,
  props: props.filter(({
    typeId: t
  }) => t === typeId)
})).filter(({
  props
}) => props.length);

console.log(result);

CodePudding user response:

You can use a filter to get the wanted typeIds then a reduce on the main array to only keep the relevant items.

This method does not modify the original array.

const array = [
    { id: 1, name: 'a1', props: [
        { name: 'b1', typeId: 1 },
        { name: 'b2', typeId: 1 },
        { name: 'b3', typeId: 5 },
        { name: 'b4', typeId: 5 },
    ] },
    { id: 2, name: 'a2', props: [
        { name: 'c1', typeId: 1 },
        { name: 'c2', typeId: 1 },
        { name: 'c3', typeId: 5 },
    ] },
    { id: 3, name: 'a3', props: [
        { name: 'd1', typeId: 5 },
        { name: 'd2', typeId: 5 },
    ] },
    { id: 4, name: 'a4', props: [
        { name: 'e1', typeId: 1 },
    ] }
];
function filterBySubTypeId(baseArray, subprop, subpropValue) {
    return baseArray.reduce((acc, val) => {
    const props = val.props.filter(prop => prop[subprop] === subpropValue); // Keep track of filtered sub-properties
    return props.length > 0 ? [...acc, {...val, props}] : acc; // Return the accumulator or the concatenated accumulator with a modified copy of the item  
  }, [])
}

console.log(filterBySubTypeId(array, 'typeId', 1))
console.log(filterBySubTypeId(array, 'typeId', 5))
console.log(filterBySubTypeId(array, 'typeId', 2)) // []

  • Related