user2953989
user2953989

Reputation: 2979

Filter array of objects by value

I want to filter an array of objects, by a specific value within the objects.

In the example i've provided I want to filter the array 'pets' by a value in the array 'characteristics'. For example, where I have called the function with the param 'loyal', i'd only expect the object for the dog value to be returned, as only the dog has that characteristic.

At the moment when I call the function both objects are returned even though only the object for dog has that value in its characteristics array.

const pets = [
  {
    name: 'dog',
    characteristics: [
      {
        value: 'loyal'
      },
      {
        value: 'big'
      }
    ]
  },
  {
    name: 'cat',
    characteristics: [
      {
        value: 'fluffy'
      },
      {
        value: 'small'
      }
    ]
  },
  ]

function filterPets(pets, characteristic) {
  return pets.filter(function(pet) {
    return pet.characteristics.filter(o => o.value.includes(characteristic));
  })
}

console.log(filterPets(pets, 'loyal'));

Upvotes: 1

Views: 284

Answers (2)

Chirume
Chirume

Reputation: 59

    function filterPets(list, charValue) {
      const filteredPets = []
        list.map(function(pet,petIndex,array) {
          pet.characteristics.map(function(charac){
            if(charac.value === charValue){
              return filteredPets.push(array[petIndex])
            }
         })
      })
      return filteredPets
    }

    filterPets(pets,'loyal');

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1074305

That's because for the characteristics check you're using filter, which always returns an array (even if a blank one), and even a blank array is a truthy value, so the outer filter keeps every pet you check. For that inner check, you want some, not filter, so you get a flag for whether any entries matched:

function filterPets(pets, characteristic) {
  return pets.filter(function(pet) {
    return pet.characteristics.some(o => o.value.includes(characteristic));
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^
  });
}

const pets = [
  {
    name: 'dog',
    characteristics: [
      {
        value: 'loyal'
      },
      {
        value: 'big'
      }
    ]
  },
  {
    name: 'cat',
    characteristics: [
      {
        value: 'fluffy'
      },
      {
        value: 'small'
      }
    ]
  },
];

function filterPets(pets, characteristic) {
  return pets.filter(function(pet) {
    return pet.characteristics.some(o => o.value.includes(characteristic));
  });
}

console.log(filterPets(pets, 'loyal'));


Just for what it's worth, I assume characteristics are unique (you can't have "loyal" twice), so you might prefer to keep those in a Set so you can check for them more easily than .some(o => o.includes(characteristic)). For instance:

const pets = [
    {
        name: "dog",
        characteristics: new Set(["loyal", "big"]),
    },
    {
        name: "cat",
        characteristics: new Set(["fluffy", "small"]),
    },
];

function filterPets(pets, characteristic) {
    return pets.filter(function(pet) {
        return pet.characteristics.has(characteristic);
    });
}

Live Example:

const pets = [
    {
        name: "dog",
        characteristics: new Set(["loyal", "big"]),
    },
    {
        name: "cat",
        characteristics: new Set(["fluffy", "small"]),
    },
];

function filterPets(pets, characteristic) {
    return pets.filter(function(pet) {
        return pet.characteristics.has(characteristic);
    });
}

console.log(filterPets(pets, "loyal"));
console.log("Don't worry about the {} for characteristics, the Stack Snippets console doesn't know how to display Set objects. Look in the real console if you want to double-check the set.");

Upvotes: 4

Related Questions