0

It's confusing to try to explain, but I want to be able to add a list of skill sets to different people objects that are in their own list.

For example: I have a Json object of people:

"people": [
    {
        "id": 1,
        "name": "Tony Rogers",
    },
    {
        "id": 2,
        "name": "Steven Grant",
    },
    {
        "id": 3,
        "name": "Peter Wilson",
    },
]

and then I have a list of skills that I want to match up with them:

"skills": [
    {
        "id": 1,
        "name": "Engineering",
        "personId": 1
    },
    {
        "id": 2,
        "name": "Painting",
        "personId": 2
    },
    {
        "id": 3,
        "name": "Chemistry",
        "personId": 3
    },
    {
        "id": 4,
        "name": "Physics",
        "personId": 1
    },
 ]

but I am unsure how to get the output I want by looping through both lists. I would preferably like to append a "skills" section onto each person that contains all of their skills.

I thought I could do something along the lines of

people.forEach(function(person){
   skills.forEach(function(skill){

      if(skill.personId == person.id){ 
         person['skills'] = {"name" : skill.name};
      }
   });
});

but it repeats a person multiple times rather than adding to their own skill list.

1
  • You're close, instead try an outer loop for the people, then find the persons id that you are currently iterating over and store it in some variable. Then loop through each skill, and stop when you find the id you just stored and add the skills. This makes sure each person only gets checked for skills once. Commented Nov 17, 2015 at 17:28

3 Answers 3

1

You need an array type to store multiple skills, so instead of just assigning person['skills'] = {"name" : skill.name}; create an array and push the new skill object to it.

people.forEach(function(person){
   skills.forEach(function(skill){

      if(skill.personId == person.id){ 

         //creates an array, if not yet created
         person['skills'] = person['skills'] || []; 

         //push the skill object to the array
         person['skills'].push(skill.name);

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

8 Comments

Hi, I tried working with this, but instead of the skill name being returned when I view the people, I just get "skills: [ [Object] ]" instead of say "skills: [ { "Engineering" } ]" or something along those lines.
@user3113376 [{ "Engineering" }] this cannot be direct string, it is an object with string property with no value. If you just want ["Engineering"], then I updated my answer as per that.
It's not efficient to do a loop in a loop if you can use just two loops in order to have the same result
@imkost Please look at the question, what OP is trying to ask. I really appreciate your performance concern. Please convince that to OP. In my answer I didn't quote anywhere that this code has good performance. But that should not be the reason to down-vote an answer.
@rajuGT, seems like you misunderstand me. I agree that your answer is absolutely correct. What I was trying to do is to notice OP about possible performance issue. I didn't down-vote you, somebody else did it and I'm not sure about the reasons (misclick maybe). Take my +1 )
|
1

If you have 20 persons and 20 skills, then it will be 20 * 20 = 400 loops!

You can do it more efficiently using just 2 loops:

var skillsByPerson = {};

skills.forEach(function(skill) {
  var personId = skill.personId;
  var personSkills = skillsByPerson[personId] || (skillsByPerson[personId] = []);

  personSkills.push({ name: skill.name });
});

people.forEach(function(person) {
  person.skills = skillsByPerson[person.id] || [];
});

Here is the jsPerf test proof for performance check.

Comments

0

You're overwriting skills on each iteration (this part: person['skills'] = {"name" : skill.name};), instead you need to push a skill into an array of skills:

var people = [
  {"id": 1, "name": "Tony Rogers",}, 
  {"id": 2, "name": "Steven Grant",}, 
  {"id": 3, "name": "Peter Wilson",}];

var skills = [{
  "id": 1,
  "name": "Engineering",
  "personId": 1
}, {
  "id": 2,
  "name": "Painting",
  "personId": 2
}, {
  "id": 3,
  "name": "Chemistry",
  "personId": 3
}, {
  "id": 4,
  "name": "Physics",
  "personId": 1
}, ]

people.forEach(function(person) {
  person['skills'] = []; // create an empty skills array for each person
  skills.forEach(function(skill) {

    if (skill.personId == person.id) {
      person['skills'].push({"name": skill.name}); // push the skill
    }
  });
});

console.log(people);

4 Comments

@user3113376 If the personId property doesn't bother you, you could use .filter() -> person["skills"] = skills.filter(function(skill) { return skill.personId === person.id; });
What do you mean "doesn't bother", @Andreas?
In the question the resulting skills array only contains the skill name. With .filter() it would also contain personId and id (but I guess this one would be negligible)
I'm pretty sure we don't need to modify the skills object, but extend the people object by adding a skills sub-object.

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.