-1

I have an array of objects, that looks like this:

data = [
  {
    title: 'John Doe',
    departments: [
      { name: 'Marketing', slug: 'marketing'},
      { name: 'Sales', slug: 'sales'},
      { name: 'Administration', slug: 'administration'},
    ]
  },
  {
    title: 'John Doe Junior',
    departments: [
      { name: 'Operations', slug: 'operations'},
      { name: 'Sales', slug: 'sales'},
    ]
  },
  {
    title: 'Rick Stone',
    departments: [
      { name: 'Operations', slug: 'operations'},
      { name: 'Marketing', slug: 'marketin'},
    ]
  },
]

How can I iterate over each object's departments array and create new arrays where I would have employees sorted by departments, so that the end result would like this:

operations = [
  {
    title: 'John Doe Junior',
    departments: [
      { name: 'Operations', slug: 'operations'},
      { name: 'Sales', slug: 'sales'},
    ]
  },
  {
    title: 'Rick Stone',
    departments: [
      { name: 'Operations', slug: 'operations'},
      { name: 'Marketing', slug: 'marketin'},
    ]
  },
]

marketing = [
  {
    title: 'John Doe',
    departments: [
      { name: 'Marketing', slug: 'marketing'},
      { name: 'Sales', slug: 'sales'},
      { name: 'Administration', slug: 'administration'},
    ]
  },
  {
    title: 'Rick Stone',
    departments: [
      { name: 'Operations', slug: 'operations'},
      { name: 'Marketing', slug: 'marketin'},
    ]
  },
]

What would be the way to create dynamically this kind of arrays?

Update

I have tried to come up with a solution using the suggestion from the answer, where I would dynamically create an array with department objects that would have an array of employees:

const isInDepartment = departmentToCheck => employer => employer.departments.find(department => department.slug == departmentToCheck);

var departments = [];
function check(departments, name) {
  return departments.some(object => name === object.department);
}

employees.forEach((employee) => {
    employee.departments.forEach((department) => {
        let found = check(departments, department.slug);
        if (!found) { 
            departments.push({ department: department.slug }); 
        }
        });
});

departments.forEach((department) => {
    // push an array of employees to each department
    //employees.filter(isInDepartment(department));
});

But, I don't know how can I push the array of employees to the object in the array that I am looping at the end? This is the fiddle.

Leff
  • 1,968
  • 24
  • 97
  • 201
  • What have you tried? You would need to use [`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#Methods_of_the_Object_constructor) and [`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#Methods_2) methods. – Sebastian Simon Sep 05 '17 at 17:36
  • @T.J.Crowder I have edited the question and fixed the syntax – Leff Sep 05 '17 at 17:40
  • What type of syntax is that? You can use console.log to output a clean representation of a variable in json like this: console.log(JSON.stringify(someVar)); – Anony372 Sep 05 '17 at 17:45
  • 1
    I have edited the question again, previously I was just copying it from the console in chrome, I apologise for that – Leff Sep 05 '17 at 17:49
  • 1
    Great! So where are you stuck? What has your research turned up? See also: https://stackoverflow.com/questions/9329446/for-each-over-an-array-in-javascript/9329476#9329476 Unless I'm missing something, this is just nested loops (of whatever your favorite flavor is from the menu on offer in that answer). *(not my dv)* – T.J. Crowder Sep 05 '17 at 17:52
  • seems like all you'd need here is .filter. nothing magic. – Kevin B Sep 05 '17 at 17:54
  • https://stackoverflow.com/search?q=group%20by%20property%20[js] – Bergi Sep 05 '17 at 18:07
  • Why is your title 'How to iterate through an array of object properties, in an array of objects". It seems like what you want to do is **group** the objects. –  Sep 05 '17 at 20:07

1 Answers1

1

How about this? I use Array.protoype.filter operation, and I use a higher-order function (in this case a function that returns a function) to create the predicate (function that returns a boolean) that will check whether an employee is in a specific department. I added some (hopefully) clarifying comments in the code.

Edit: with the new code and context you provided this JSFiddle demo shows how it would work together.

const employees = [
  {
    title: 'John Doe',
    departments: [
      { name: 'Marketing', slug: 'marketing'},
      { name: 'Sales', slug: 'sales'},
      { name: 'Administration', slug: 'administration'}
    ]
  },
  {
    title: 'John Doe Junior',
    departments: [
      { name: 'Operations', slug: 'operations'},
      { name: 'Sales', slug: 'sales'}
    ]
  },
  {
    title: 'Rick Stone',
    departments: [
      { name: 'Operations', slug: 'operations'},
      { name: 'Marketing', slug: 'marketin'}
    ]
  }
];

// given a department, this returns a function that checks
// whether an employee is in the specified department
// NOTE: the "find" returns the found object (truthy) 
// or undefined (falsy) if no match was found.
const isInDepartment = 
 departmentToCheck =>
     employee => employee.departments.find(dep => dep.name == departmentToCheck);

const employeesInMarketing = employees.filter(isInDepartment('Marketing'));
const employeesInOperations = employees.filter(isInDepartment('Operations'));

console.log('Employees in marketing', employeesInMarketing);
console.log('Employees in operations', employeesInOperations);
jonahe
  • 4,820
  • 1
  • 15
  • 19
  • I fail to understand the reason for downvoting this. It could use more explanation, but that's nothing like a reason to downvote it. – T.J. Crowder Sep 05 '17 at 18:03
  • Thanks. Well, it was a very quick down-vote (instant as far as I could tell) so I started wondering if it was some automatic downvote for when you answer a question with negative score? (Havent't head of any such rule before, but it would make *some* sense). Btw. I added some comments to the code. Do you think there's more room for explanation? If so, where? – jonahe Sep 05 '17 at 18:20
  • 1
    Thank you very much for your suggestion, I have updated my question with your code, I am trying to dynamically create an array with departments object, that would then check the employees, but for some reason, I don't get distinct values with my function found. – Leff Sep 05 '17 at 19:22
  • 1
    You forgot to return from your `found` function. It should be `return departments.some(function (el) .... ...`. And if you are just interested in the department names as strings, then you can push the strings directly (not pushing a new object with the string as a property) – jonahe Sep 05 '17 at 19:31
  • I edited my answer with this new info. Hope it helps. Tell me if there's something I should explain or elaborate on :) – jonahe Sep 05 '17 at 19:44
  • Sorry for the multiple comments in a row. I just wanted to say thanks for reminding me that the `some` function existed. You can replace `employer.departments.find` with `.some`. I think it's clearer. Especially if we name the function inside `some`. Like this https://jsfiddle.net/jonahe/hwm7xdf4/73/ . I like it when the code starts to read more like (somewhat weird) English: for example : `employer.departments.some(departmentMatchesName(departmentToCheck))` translates roughly to the sentence "The employee's departments has some department that matches the name we are checking". – jonahe Sep 05 '17 at 20:06
  • 1
    Thank you so much for your answer, that was exactly what I was looking for! Thanks again! – Leff Sep 05 '17 at 20:08
  • You're welcome! :) Comment here if you have further questions or anything like that. Good luck! – jonahe Sep 05 '17 at 20:10