2

My problem goes this way; I have an array of courses, each one has its name and array consisting of lessons (Each lesson has its own days).

I.e.:

courses = [
  {name: 'Math', lessons: [{day: 'Wednesday'}, {day: 'Thursday'}]},
  {name: 'Sports', lessons: [{day: 'Monday'}]}
]

My desired result is:

courses_flattened = [
  {name: 'Math', lesson: {day: 'Wednesday'}},
  {name: 'Math', lesson: {day: 'Thursday'}},
  {name: 'Sports', lesson: {day: 'Monday'}}
]

Currently what I'm doing is using array.map to iterate over the courses, then for each course I'm returning an array consisting of all lessons times. After receiving an array of arrays, I'm using:

courses_flattened = [].concat.apply([], courses_flat)

to get an array consisting of all courses with 1 lesson each.

Full code:

courses_flat = courses.map((course) -> {
  var lessons = [];
  course.lessons.forEach((lesson) -> {
    lessons.push({name: course.name, lesson: {day: lesson.day}})
  });
  return lessons;
});

Is there a nicer way for receiving this kind of result?

Using Lodash is an option for me.

3
  • Could the downvoter please explain why? Commented Feb 4, 2018 at 21:30
  • @JonasW. Indeed, this was a perfectly explained question. The only reason I can think of the downvote is it's maybe best in code review. Commented Feb 4, 2018 at 21:32
  • 2
    The close vote is even more funny... How can this be "to broad" ??! Commented Feb 4, 2018 at 21:33

3 Answers 3

2

Nested loops can be rewritten with flatMap. It's not built-in in JS, but you can define it easily like this:

let flatMap = (a, fn) => [].concat(...a.map(fn));

(Note that this is essentially your [].concat.apply thing).

and then

courses_flattened = flatMap(courses, ({name, lessons}) => 
     lessons.map(lesson => ({name, lesson})));

With lodash it's the same:

courses_flattened = _.flatMap(courses, ({name, lessons}) => 
     _.map(lessons, lesson => ({name, lesson})));
Sign up to request clarification or add additional context in comments.

Comments

1

const courses = [
  {name: 'Math', lessons: [{day: 'Wednesday'}, {day: 'Thursday'}]},
  {name: 'Sports', lessons: [{day: 'Monday'}]}
];

const result = [];

for(const {name, lessons} of courses)
  for(const {day} of lessons)
    result.push({name, lesson: { day }});
    
console.log(result);

Just use two nested for loops maybe? ( And object destructuring)

2 Comments

Such lovely code, would look much more lovely inside a snippet.. :)
@keith because then you dont even need to read through it to check if it works, you can just click on "run snippet", check the result, copy + paste and ask the next question... But yes, the <> button does not exist on touch devices..
0

In plain ES6 JavaScript you could use reduce, map and destructuring to get to this solution:

const courses = [{name: 'Math', lessons: [{day: 'Wednesday'}, {day: 'Thursday'}]},{name: 'Sports', lessons: [{day: 'Monday'}]}];

const result = courses.reduce( (acc, {name, lessons}) =>
    acc.concat(lessons.map( lesson => ({ name, lesson }) ))
, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Comments

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.