1

I have an array that looks like this:

let movies = [
  'terminator.1',
  'terminator.2',
  'terminator.3',
  'harry-potter.1',
  'harry-potter.3',
  'harry-potter.2',
  'star-wars.1'
]

and I would like to have an object like this:

{
  "terminator": [1,2,3],
  "harry-potter": [1,2,3],
  "star-wars": [1]
}

so far I'm able to have an object like this

{
  { terminator: [ '1' ] },
  { terminator: [ '2' ] },
  { terminator: [ '3' ] },
  { 'harry-potter': [ '1' ] },
  { 'harry-potter': [ '3' ] },
  { 'harry-potter': [ '2' ] },
  { 'star-wars': [ '1' ] }
}

I would like to know if there is a way to check during an Array.map when I'm generating my object if there is already a certain key and if there is to push the value to the corresponding array instead of creating a new key-value pair.

This is the code that I currently use for my solution. Thanks in advance.

let movies = [
  'terminator.1',
  'terminator.2',
  'terminator.3',
  'harry-potter.1',
  'harry-potter.3',
  'harry-potter.2',
  'star-wars.1'
]

let t = movies.map(m => {
  let [name, number] = [m.split('.')[0],m.split('.')[1]]
  return {[name]: [number]}
})

console.log(t)
OmarAguinaga
  • 707
  • 1
  • 8
  • 17

3 Answers3

3

You can do this with a single Array.reduce and one array destructuring in order to get the key/value combination:

let movies = [ 'terminator.1', 'terminator.2', 'terminator.3', 'harry-potter.1', 'harry-potter.3', 'harry-potter.2', 'star-wars.1' ]

const result = movies.reduce((r,c) => {
  let [k,v] = c.split('.')
  r[k] = [...r[k] || [], +v]
  return r
},{})

console.log(result)
Akrion
  • 18,117
  • 1
  • 34
  • 54
  • This works as expected and love the es6 features. I'll mark @ibrahim answer as the correct solution since he was the first to respond and it's fine but thank you very much! – OmarAguinaga Dec 03 '18 at 08:30
2

const movies = ['terminator.1', 'terminator.2', 'terminator.3', 'harry-potter.1', 'harry-potter.3', 'harry-potter.2', 'star-wars.1']

const moviesMap = {}

movies.forEach(data => {
  const [title, id] = data.split('.')
  if (moviesMap[title]) {
    moviesMap[title].push(id)
  } else {
    moviesMap[title] = [id]
  }
})

console.log(moviesMap)
Gio
  • 36
  • 1
1

That's a job for Array#reduce, not Array#map:

let t = movies.reduce((acc, movie) => {             // for each movie in movies
   let [name, number] = movie.split('.');           // split the movie by "." and store the first part in name and the second in number
   if(acc[name]) {                                  // if the accumulator already has an entry for this movie name
      acc[name].push(number);                       // then push this movie number into that entry's array
   } else {                                         // otherwise
      acc[name] = [number];                         // create an entry for this movie name that initially contains this movie number
   }
   return acc;
}, Object.create(null));                            // Object.create(null) is better than just {} as it creates a prototypeless object which means we can do if(acc[name]) safely

Note: If you want to coerce the numbers into actual numbers and not keep them as strings, then use the unary + to implicitly convert them: +number.

Example:

let movies = [ 'terminator.1', 'terminator.2', 'terminator.3', 'harry-potter.1', 'harry-potter.3', 'harry-potter.2', 'star-wars.1' ];

let t = movies.reduce((acc, movie) => {
   let [name, number] = movie.split(".");
   if(acc[name]) {
      acc[name].push(number);
   } else {
      acc[name] = [number];
   }
   return acc;
}, Object.create(null));

console.log(t);
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73