0

Suppose I got this array:

const users =[ 
   { 
      id:1,
      name:'bob',

   },
   { 
      id:2,
      name:'sally',

   },
   { 
      id:3,
      name:'bob',
      age:30,

   }
];

And I want to use any key(in this case 'name' ) to return an object :

{ 
   bob:[ 
      { 
         id:1,
         name:'bob',

      },
      { 
         id:3,
         name:'bob',
         age:30,

      }
   ],
   sally:[ 
      { 
         id:2,
         name:'sally',

      }
   ],
}

I tried this:

const go = (A,key) =>{
    return A.reduce((o, key) => ({ ...o, [key]:o }), {})
}

export default go;

But this returns:

{ '[object Object]': { '[object Object]': { '[object Object]': {} } } }

If the key is not present omit from the result. It should not mutate the original array though. How can I perform this kind of conversion?

2 Answers 2

1

With the approach you have, a new array is not instantiated in case the key is not yet present in the object.

This will work:

const result = users.reduce((a, v) => {
  a[v.name] = a[v.name] || [];
  a[v.name].push(v);
  return a;
}, {});

Complete snippet wrapping this logic in a function:

const users = [{
  id: 1,
  name: 'bob',

}, {
  id: 2,
  name: 'sally',

}, {
  id: 3,
  name: 'bob',
  age: 30,

}];

const go = (input, key) => input.reduce((a, v) => {
  a[v[key]] = a[v[key]] || [];
  a[v[key]].push(v);
  return a;
}, {});

console.log(go(users, 'name'));


If you really want to cram it into a one-liner, this will also work, by either spreading the already existing array, or an empty one:

const result = users.reduce((a, v) => ({...a, [v.name]: [...a[v.name] || [], v]}), {});

Complete snippet wrapping this logic in a function:

const users = [{
  id: 1,
  name: 'bob',

}, {
  id: 2,
  name: 'sally',

}, {
  id: 3,
  name: 'bob',
  age: 30,

}];

const go = (input, key) => input.reduce((a, v) => ({...a, [v[key]]: [...a[v[key]] || [], v]}), {});

console.log(go(users, 'name'));

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

7 Comments

This works only for the parameter 'name'. It does not if I input the parameter 'id'.
Just needs to be wrapped in a function that also accepts the property name.
I edited the snippets to wrap the logic in a function.
If I use the age parameter it returns the undefined array. How can I skip the objects that are undefined?
First filter out only those that have the property set: input.filter(v => v.key != null).reduce(...)
|
0

You were close but the key attribute in this case was each value (eg: { id: 1, name: 'bob' }) so the string representation is [object Object] which is why all the keys are that. Based off what you said, you want to use key.name as the property and set it's value as [key]. (I renamed key to arr in my example since it's the array value).

So this would be something like { ...o, [arr.name]: [arr] }

Because there can be an existing value, it adds a bit of complexity which is what [...(obj[arr.name] || []), arr] is doing. It's looking up the existing value (or defaulting to an empty array) and spreading those values and adding the new value.

const users = [{
    id: 1,
    name: 'bob',

  },
  {
    id: 2,
    name: 'sally',

  },
  {
    id: 3,
    name: 'bob',
    age: 30,

  }
];


const transform = (input, keyName) => {
  return input.reduce((obj, arr) => ({ ...obj,
    [arr[keyName]]: [...(obj[arr[keyName]] || []), arr]
  }), {})
}

console.log(transform(users, 'name'))
console.log(transform(users, 'id'))

6 Comments

This works only for the parameter 'name'. It does not if I input the parameter 'id'.
@bierhier ah I see what you were trying to do now. Got it. I updated the answer to handle a dynamic key.
if I use 'age' as a parameter I still get the undefined objects returned?
Because bob and sally do not have an age. So both of those are undefined. Try adding age to both of those.
I don't want to change the input.
|

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.