PWT
PWT

Reputation: 43

Search through array in an object using javascript without using a loop

I want to find a better, more elegant solution than using 2 iteration to find a value in an object. I looked at functions to search within an array such as find,indexOf but was wondering I could search through the object without using a for or forEach.

Let say I want to find all swimmers. What I got so far.

members = [
  { name: "Sue", hobby: ["Swimming", "Running", "Dancing"] },
  { name: "Sam", hobby: ["Cars", "Travelling"] },
  { name: "John", hobby: ["Reading", "Swimming"] },
  { name: "Rob", hobby: ["Running", "Coding"] },      
];
function findSwimmers(members, hobby) {      
  let swimmers = [];      
  members.forEach(function (e){        
    e.hobby.forEach(function (element){          
      if (element.toLowerCase() === hobby.toLowerCase()) {
        swimmers.push(e);
      }
    });
  });
  return swimmers;
}

Upvotes: 2

Views: 205

Answers (5)

KooiInc
KooiInc

Reputation: 122916

First solution: bit of a hack but hey, no looping

Second solution: using Array.findIndex may reduce the amount of iterations in the inner loop (well, at least gives you some probability of less iterations) because (MDN):

... If such an element is found, findIndex immediately returns the index for that iteration ...

const findMembersWithValueForKey = (members, key, value) => 
  members.filter(member => member[key] instanceof Array
    && `#${member[key].join("#")}#`.toLowerCase()
         .indexOf(`#${value.toLowerCase()}#`) > -1
    || false);
    
const findMembersWithValueForKey2 = (members, key, value) => {
    value = value.toLowerCase();
    return members.filter(member => 
      member[key] instanceof Array
      && member[key].findIndex(v => v.toLowerCase() === value) > -1
      || false);
};
    
const members = [
  { name: "Sue", hobby: ["Swimming", "Running", "Dancing"] },
  { name: "Sam", hobby: ["Cars", "Travelling"] },
  { name: "John", hobby: ["Reading", "Swimming"] },
  { name: "Rob", hobby: ["Running", "Coding"] },      
];

console.log(findMembersWithValueForKey(members, "hobby", "swimming"));

console.log(findMembersWithValueForKey2(members, "hobby", "swimming"));

Upvotes: 0

Mihai Alexandru-Ionut
Mihai Alexandru-Ionut

Reputation: 48367

You can use filter in combination with some by passing callback functions as argument.

let members = [
  { name: "Sue", hobby: ["Swimming", "Running", "Dancing"] },
  { name: "Sam", hobby: ["Cars", "Travelling"] },
  { name: "John", hobby: ["Reading", "Swimming"] },
  { name: "Rob", hobby: ["Running", "Coding"] },      
];

function findSwimmers(members, hobby) {      
  return members_swimming = members.filter(({hobby}) => hobby.some(item => item == "Swimming"));
                                
}

console.log(findSwimmers(members, "Swimming"));

Upvotes: 5

T.J. Crowder
T.J. Crowder

Reputation: 1074495

Any solution is going to involve loops. The only question is whether the loops are in your code or a function you call.

In your case, filter and some seem like the tools to use:

function findSwimmers(members, hobby) {
  hobby = hobby.toLowerCase();
  return members.filter(member =>
    member.hobby.some(h => h.toLowerCase() === hobby)
  );
}

You might want a different function name. :-)

Live Example:

const members = [
  { name: "Sue", hobby: ["Swimming", "Running", "Dancing"] },
  { name: "Sam", hobby: ["Cars", "Travelling"] },
  { name: "John", hobby: ["Reading", "Swimming"] },
  { name: "Rob", hobby: ["Running", "Coding"] },      
];
function findSwimmers(members, hobby) {
  hobby = hobby.toLowerCase();
  return members.filter(member =>
    member.hobby.some(h => h.toLowerCase() === hobby)
  );
}

console.log(findSwimmers(members, "swimming"));
.as-console-wrapper {
  max-height: 100% !important;
}

Note that your original code didn't stop looping when it found a hobby match (and if there were duplicate entries in the hobbies array, would have added the same member more than once — but presumably there aren't meant to be duplicates in that array).

You might also use String#localeCompare, if available, with the sensitivity: "base" option rather than comparing lower-case strings.

Upvotes: 1

Ankit Agarwal
Ankit Agarwal

Reputation: 30739

You can use Array.filter() and Array.map() with destructuring:

var members = [
  { name: "Sue", hobby: ["Swimming", "Running", "Dancing"] },
  { name: "Sam", hobby: ["Cars", "Travelling"] },
  { name: "John", hobby: ["Reading", "Swimming"] },
  { name: "Rob", hobby: ["Running", "Coding"] },      
];
var swimmers = members.filter(({hobby}) => hobby.includes('Swimming')).map(({name}) => name);
console.log(swimmers)

Upvotes: 2

lordchancellor
lordchancellor

Reputation: 4107

You can achieve this with a single line:

let swimmers = members.filter(person => person.hobby.includes('Swimming'));

Upvotes: 0

Related Questions