207

How can I transform a big object to array with lodash?

var obj = {
  22: {name:"John", id:22, friends:[5,31,55], works:{books:[], films:[],}
  12: {name:"Ivan", id:12, friends:[2,44,12], works:{books:[], films:[],}
}

// transform to 
var arr = [{name:"John", id:22...},{name:"Ivan", id:12...}]
Let Me Tink About It
  • 15,156
  • 21
  • 98
  • 207
siavolt
  • 6,869
  • 5
  • 24
  • 27
  • 3
    @Mritunjay Yes because the docs have such a great overview of the library... not. It's just an exhaustive list of functions and going through each one could well prove a waste of time if there isn't one. The question is a fair one. – Epirocks Mar 10 '20 at 12:50

12 Answers12

313

You can do

var arr = _.values(obj);

For documentation see here.

Daniel Schmidt
  • 11,605
  • 5
  • 38
  • 70
  • 48
    What about if you wanted to preserve the key as a property? (in this example, if the `id` property did not exist and you wanted to create it based on the key of each object. – Michael Liquori Mar 07 '16 at 20:02
  • 8
    You could do something like this: `var arr = _.values(_.mapKeys(obj, function(value, key) { value.id = key; return value; }));` – Daniel Schmidt Mar 08 '16 at 07:48
  • 2
    @DanielSchmidt I'm not sure what I did wrong but that sample only returned 1 row for me. :( So what I did is manually push the `return` value to an array like this: `const divisionsList = []; _.mapKeys(divisions, (value, key) => { divisionsList[key] = value; });` I'd appreciate any comments or suggestions to improve this approach. – JohnnyQ Sep 26 '16 at 07:34
  • 9
    @JohnnyQ I think you'll need to use mapValues instead e.g. `const toArrayWithKey = (obj, keyAs) => _.values(_.mapValues(obj, (value, key) => { value[keyAs] = key; return value; }));` – orjan Oct 06 '16 at 19:40
  • 1
    @orjan Yes I actually figured this out, just forgot to update. Thank you for that. – JohnnyQ Oct 07 '16 at 05:01
56

A modern native solution if anyone is interested:

const arr = Object.keys(obj).map(key => ({ key, value: obj[key] }));

or (not IE):

const arr = Object.entries(obj).map(([key, value]) => ({ key, value }));
Dominic
  • 62,658
  • 20
  • 139
  • 163
49
_.toArray(obj);

Outputs as:

[
  {
    "name": "Ivan",
    "id": 12,
    "friends": [
      2,
      44,
      12
    ],
    "works": {
      "books": [],
      "films": []
    }
  },
  {
    "name": "John",
    "id": 22,
    "friends": [
      5,
      31,
      55
    ],
    "works": {
      "books": [],
      "films": []
    }
  }
]"
Jivings
  • 22,834
  • 6
  • 60
  • 101
21

For me, this worked:

_.map(_.toPairs(data), d => _.fromPairs([d]));

It turns

{"a":"b", "c":"d", "e":"f"} 

into

[{"a":"b"}, {"c":"d"}, {"e":"f"}]
Mohammad Usman
  • 37,952
  • 20
  • 92
  • 95
NoNine
  • 333
  • 2
  • 6
  • 1
    I needed to transform an object into an Array, in a way that each key/value of the original object would be a {key:value}-object in the array. _.toPairs(data) takes the object {"a":"b", "c":"d", "e":"f"} and returns it as an array of arrays like [["a":"b"], ["c":"d"], ["e":"f"]]. _.fromPairs does the opposite, it takes an Array with 2 elements: ["a","b"] and returns it as an object: {"a":"b"}. Using _.map I iterated over the array if arrays created by _.toPairs to transform it into an array of objects with the help of _.fromPairs. – NoNine Sep 23 '17 at 18:07
  • 1
    I am glad I scrolled down to see this. Your solution worked for me! Thanks! – Wale Aug 04 '18 at 17:44
  • 1
    @NoNine You don't need to apply map on a array (of array), you can directly apply it on the input object, and return each key value pair `_.map(data, (v,k)=>({[k]: v}))` see my answer for detail. `_.toPairs` and `_fromPairs` is additional and unnecessary here. – Koushik Chatterjee Sep 26 '18 at 14:20
  • This is not what the question is meant for. because it's a bit dificult to use the result as each entry contain a key (which you don'y know) and again you need to go through some logic (eg Object.keys or Object.values) for each separate entry to get value of each, if toy want to preserve the keys then you can create a array of objects that stuctrured like `[{key: 'someKey', val: 'The value'}, {....},...]` – Koushik Chatterjee Nov 12 '18 at 09:43
20

There are quite a few ways to get the result you are after. Lets break them in categories:

ES6 Values only:

Main method for this is Object.values. But using Object.keys and Array.map you could as well get to the expected result:

Object.values(obj)
Object.keys(obj).map(k => obj[k])

var obj = {
  A: {
    name: "John"
  },
  B: {
    name: "Ivan"
  }
}

console.log('Object.values:', Object.values(obj))
console.log('Object.keys:', Object.keys(obj).map(k => obj[k]))

ES6 Key & Value:

Using map and ES6 dynamic/computed properties and destructuring you can retain the key and return an object from the map.

Object.keys(obj).map(k => ({[k]: obj[k]}))
Object.entries(obj).map(([k,v]) => ({[k]:v}))

var obj = {
  A: {
    name: "John"
  },
  B: {
    name: "Ivan"
  }
}

console.log('Object.keys:', Object.keys(obj).map(k => ({
  [k]: obj[k]
})))
console.log('Object.entries:', Object.entries(obj).map(([k, v]) => ({
  [k]: v
})))

Lodash Values only:

The method designed for this is _.values however there are "shortcuts" like _.map and the utility method _.toArray which would also return an array containing only the values from the object. You could also _.map though the _.keys and get the values from the object by using the obj[key] notation.

Note: _.map when passed an object would use its baseMap handler which is basically forEach on the object properties.

_.values(obj)
_.map(obj)
_.toArray(obj)
_.map(_.keys(obj), k => obj[k])

var obj = {
  A: {
    name: "John"
  },
  B: {
    name: "Ivan"
  }
}

console.log('values:', _.values(obj))
console.log('map:', _.map(obj))
console.log('toArray:', _.toArray(obj))
console.log('keys:', _.map(_.keys(obj), k => obj[k]))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

Lodash Key & Value:

// Outputs an array with [[KEY, VALUE]]
_.entries(obj)
_.toPairs(obj)

// Outputs array with objects containing the keys and values
_.map(_.entries(obj), ([k,v]) => ({[k]:v}))
_.map(_.keys(obj), k => ({[k]: obj[k]}))
_.transform(obj, (r,c,k) => r.push({[k]:c}), [])
_.reduce(obj, (r,c,k) => (r.push({[k]:c}), r), [])

var obj = {
  A: {
    name: "John"
  },
  B: {
    name: "Ivan"
  }
}

// Outputs an array with [KEY, VALUE]
console.log('entries:', _.entries(obj))
console.log('toPairs:', _.toPairs(obj))

// Outputs array with objects containing the keys and values
console.log('entries:', _.map(_.entries(obj), ([k, v]) => ({
  [k]: v
})))
console.log('keys:', _.map(_.keys(obj), k => ({
  [k]: obj[k]
})))
console.log('transform:', _.transform(obj, (r, c, k) => r.push({
  [k]: c
}), []))
console.log('reduce:', _.reduce(obj, (r, c, k) => (r.push({
  [k]: c
}), r), []))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

Note that in the above examples ES6 is used (arrow functions and dynamic properties). You can use lodash _.fromPairs and other methods to compose an object if ES6 is an issue.

Akrion
  • 18,117
  • 1
  • 34
  • 54
13

If you want the key (id in this case) to be a preserved as a property of each array item you can do

const arr = _(obj) //wrap object so that you can chain lodash methods
            .mapValues((value, id)=>_.merge({}, value, {id})) //attach id to object
            .values() //get the values of the result
            .value() //unwrap array of objects
Sello Mkantjwa
  • 1,798
  • 1
  • 20
  • 36
9

Transforming object to array with plain JavaScript's(ECMAScript-2016) Object.values:

var obj = {
    22: {name:"John", id:22, friends:[5,31,55], works:{books:[], films:[]}},
    12: {name:"Ivan", id:12, friends:[2,44,12], works:{books:[], films:[]}}
}

var values = Object.values(obj)

console.log(values);

If you also want to keep the keys use Object.entries and Array#map like this:

var obj = {
    22: {name:"John", id:22, friends:[5,31,55], works:{books:[], films:[]}},
    12: {name:"Ivan", id:12, friends:[2,44,12], works:{books:[], films:[]}}
}

var values = Object.entries(obj).map(([k, v]) => ({[k]: v}))

console.log(values);
BlackBeard
  • 10,246
  • 7
  • 52
  • 62
9

Object to Array

Of all the answers I think this one is the best:

let arr = Object.entries(obj).map(([key, val]) => ({ key, ...val }))

that transforms:

{
  a: { p: 1, q: 2},
  b: { p: 3, q: 4}
}

to:

[
  { key: 'a', p: 1, q: 2 }, 
  { key: 'b', p: 3, q: 4 }
]

Array to Object

To transform back:

let obj = arr.reduce((obj, { key, ...val }) => { obj[key] = { ...val }; return obj; }, {})

To transform back keeping the key in the value:

let obj = arr.reduce((obj, { key, ...val }) => { obj[key] = { key, ...val }; return obj; }, {})

Will give:

{
  a: { key: 'a', p: 1, q: 2 },
  b: { key: 'b', p: 3, q: 4 }
}

For the last example you can also use lodash _.keyBy(arr, 'key') or _.keyBy(arr, i => i.key).

orad
  • 15,272
  • 23
  • 77
  • 113
8

2017 update: Object.values, lodash values and toArray do it. And to preserve keys map and spread operator play nice:

// import { toArray, map } from 'lodash'
const map = _.map

const input = {
  key: {
    value: 'value'
  }
}

const output = map(input, (value, key) => ({
  key,
  ...value
}))

console.log(output)
// >> [{key: 'key', value: 'value'}])
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
Vladimir Chervanev
  • 1,574
  • 1
  • 12
  • 14
5

var arr = _.map(obj)

You can use _.map function (of both lodash and underscore) with object as well, it will internally handle that case, iterate over each value and key with your iteratee, and finally return an array. Infact, you can use it without any iteratee (just _.map(obj)) if you just want a array of values. The good part is that, if you need any transformation in between, you can do it in one go.

Example:

var obj = {
    key1: {id: 1, name: 'A'},
    key2: {id: 2, name: 'B'},
    key3: {id: 3, name: 'C'}
};

var array1 = _.map(obj, v=>v);
console.log('Array 1: ', array1);

/*Actually you don't need the callback v=>v if you
are not transforming anything in between, v=>v is default*/

//SO simply you can use
var array2 = _.map(obj);
console.log('Array 2: ', array2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

However, if you want to transform your object you can do so, even if you need to preserve the key, you can do that ( _.map(obj, (v, k) => {...}) with additional argument in map and then use it how you want.

However there are other Vanilla JS solution to this (as every lodash solution there should pure JS version of it) like:

  • Object.keys and then map them to values
  • Object.values (in ES-2017)
  • Object.entries and then map each key/value pairs (in ES-2017)
  • for...in loop and use each keys for feting values

And a lot more. But since this question is for lodash (and assuming someone already using it) then you don't need to think a lot about version, support of methods and error handling if those are not found.

There are other lodash solutions like _.values (more readable for specific perpose), or getting pairs and then map and so on. but in the case your code need flexibility that you can update it in future as you need to preserve keys or transforming values a bit, then the best solution is to use a single _.map as addresed in this answer. That will bt not that difficult as per readability also.

Koushik Chatterjee
  • 4,106
  • 3
  • 18
  • 32
4

If you want some custom mapping (like original Array.prototype.map) of Object into an Array, you can just use _.forEach:

let myObject = {
  key1: "value1",
  key2: "value2",
  // ...
};

let myNewArray = [];

_.forEach(myObject, (value, key) => {
  myNewArray.push({
    someNewKey: key,
    someNewValue: value.toUpperCase() // just an example of new value based on original value
  });
});

// myNewArray => [{ someNewKey: key1, someNewValue: 'VALUE1' }, ... ];

See lodash doc of _.forEach https://lodash.com/docs/#forEach

Gil Epshtain
  • 8,670
  • 7
  • 63
  • 89
1

We should not use _.values, we should use import the method and use:

    import { values } from 'lodash';

    enum ProductCode {
      ORR = 'ORR',
      MMHS = 'MMHS',
      STTU = 'STTU',
      OOS = 'OOS'
    }
    const arr =  values(ProductCode);
    console.log(arr);
Shubham Verma
  • 8,783
  • 6
  • 58
  • 79