admin管理员组

文章数量:1128674

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...}]

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...}]
Share Improve this question edited Jul 18, 2019 at 7:17 Let Me Tink About It 16k21 gold badges107 silver badges216 bronze badges asked Jul 10, 2014 at 10:49 siavoltsiavolt 7,0675 gold badges25 silver badges27 bronze badges 1
  • 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 Commented Mar 10, 2020 at 12:50
Add a comment  | 

12 Answers 12

Reset to default 314

You can do

var arr = _.values(obj);

For documentation see here.

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 }));
_.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": []
    }
  }
]"

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"}]

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.

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

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).

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);

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>

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.

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

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);

本文标签: javascripttransform object to array with lodashStack Overflow