преобразовать объект в массив с помощью lodash

165

Как я могу превратить большой objectв arrayс 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...}]
siavolt
источник
@Mritunjay Да, потому что документы имеют такой большой обзор библиотеки ... нет. Это просто исчерпывающий список функций, и прохождение каждой из них может оказаться пустой тратой времени, если его нет. Вопрос справедливый.
Epirocks

Ответы:

265

Ты можешь сделать

var arr = _.values(obj);

Для документации см. Здесь.

Даниэль Шмидт
источник
34
А что, если вы хотите сохранить ключ как свойство? (в этом примере, если idсвойство не существует и вы хотите создать его на основе ключа каждого объекта.
Майкл Ликори
8
Вы могли бы сделать что-то вроде этого:var arr = _.values(_.mapKeys(obj, function(value, key) { value.id = key; return value; }));
Даниэль Шмидт
1
@DanielSchmidt Я не уверен, что я сделал неправильно, но этот пример вернул мне только 1 строку. :( То, что я сделал, это вручную поместил returnзначение в массив следующим образом: const divisionsList = []; _.mapKeys(divisions, (value, key) => { divisionsList[key] = value; });я был бы признателен за любые комментарии или предложения по улучшению этого подхода.
JohnnyQ
8
@JohnnyQ Я думаю , вам нужно использовать mapValues вместо напримерconst toArrayWithKey = (obj, keyAs) => _.values(_.mapValues(obj, (value, key) => { value[keyAs] = key; return value; }));
Ørjan
1
@orjan Да, я действительно понял это, просто забыл обновить. Спасибо вам за это.
JohnnyQ
38
_.toArray(obj);

Выходы как:

[
  {
    "name": "Ivan",
    "id": 12,
    "friends": [
      2,
      44,
      12
    ],
    "works": {
      "books": [],
      "films": []
    }
  },
  {
    "name": "John",
    "id": 22,
    "friends": [
      5,
      31,
      55
    ],
    "works": {
      "books": [],
      "films": []
    }
  }
]"
Jivings
источник
1
_.toArray () отлично работает @jivings
Сайед Заин Али
4
для получения только значений это хороший вариант, но toArrayнет способа сохранить ключи при необходимости.
Кушик Чаттерджи
33

Современное нативное решение, если кому-то интересно:

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

или (не IE):

const arr = Object.entries(obj).map(([key, value]) => ({ key, value }));
Dominic
источник
2
почему не простоObject.keys(obj).map(key=>({key,value: obj[key]}))
Кушик Чаттерджи
1
Мне нравится, что это даже не пользователь lodash, молодец, сэр!
HungryPipo
1
@Dominic Теперь вы изменили свой полный ответ и взяли его из моего комментария, даже без упоминания (вы это отредактировали). Молодцы 👏 😁😁
Чаттерджи
1
@KoushikChatterjee добавил его обратно
Доминик
2
Будет ли это более полезным? const arr = Object.keys(obj).map(id => ({ id, ...obj[id] })); это приведет весь объект в возвращенные данные нет? (используя 'id', так как первоначальный аскер хотел сохранить свой ключ в качестве id)
забаат
20

Для меня это сработало:

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

Получается

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

в

[{"a":"b"}, {"c":"d"}, {"e":"f"}]
NoNine
источник
1
Мне нужно было преобразовать объект в массив, таким образом, чтобы каждый ключ / значение исходного объекта был объектом {key: value} в массиве. _.toPairs (данные) принимает объект {"a": "b", "c": "d", "e": "f"} и возвращает его в виде массива массивов, подобных [["a": " b "], [" c ":" d "], [" e ":" f "]]. _.fromPairs делает противоположное, он берет массив с 2 элементами: ["a", "b"] и возвращает его как объект: {"a": "b"}. Используя _.map, я перебрал массив, если массивы, созданные _.toPairs, преобразовали его в массив объектов с помощью _.fromPairs.
NoNine
1
Я рад, что прокрутил вниз, чтобы увидеть это. Ваше решение сработало для меня! Спасибо!
Уэйл
@NoNine Вам не нужно применять карту к массиву (массива), вы можете напрямую применить ее к входному объекту и вернуть каждую пару ключ-значение, _.map(data, (v,k)=>({[k]: v}))подробнее см. Мой ответ. _.toPairsи _fromPairsявляется дополнительным и ненужным здесь.
Кушик Чаттерджи
Это не то, для чего предназначен вопрос. потому что немного сложно использовать результат, так как каждая запись содержит ключ (который вы не знаете), и снова вам нужно пройти некоторую логику (например, Object.keys или Object.values) для каждой отдельной записи, чтобы получить значение каждый, если игрушка хочет сохранить ключи, то вы можете создать массив объектов, которые структурированы как[{key: 'someKey', val: 'The value'}, {....},...]
Koushik Chatterjee
13

Есть немало способов получить желаемый результат. Давайте разбить их на категории:

Только значения ES6 :

Основным методом для этого является Object.values . Но используя Object.keys и Array.map, вы также можете получить ожидаемый результат:

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

ES6 Key & Value :

Используя карту и ES6 динамические / вычисленные свойства и деструктурирование, вы можете сохранить ключ и вернуть объект с карты.

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

Только Lodash Values :

Метод, разработанный для этого, _.valuesоднако, есть как «горячие клавиши» _.mapи вспомогательный метод, _.toArrayкоторый также возвращает массив, содержащий только значения из объекта. Вы могли бы также , _.mapхотя _.keysи получить значения из объекта с помощью obj[key]нотации.

Примечание: _.mapпри передаче объект будет использовать свой baseMapобработчик, который в основном зависит forEachот свойств объекта.

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

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), [])

Обратите внимание, что в приведенных выше примерах используется ES6 (функции стрелок и динамические свойства). Вы можете использовать lodash _.fromPairsи другие методы для создания объекта, если ES6 является проблемой.

Akrion
источник
12

Если вы хотите, чтобы ключ (в данном случае id) был сохранен как свойство каждого элемента массива, вы можете сделать

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
источник
8

Обновление 2017: Object.values , значения lodash и toArray делают это. А для сохранения ключей карты и распространения оператора играть приятно:

// 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>

Владимир Черванев
источник
7

Преобразование объекта в массив с помощью простого JavaScript ( 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);

Если вы также хотите сохранить использование ключей Object.entriesи Array#mapвот так:

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

Бороды
источник
5

var arr = _.map(obj)

Вы также можете использовать _.mapфункцию (и того lodashи другого underscore) object, она будет внутренне обрабатывать этот случай, перебирать каждое значение и ключ с вашим итератором и, наконец, возвращать массив. Infact, вы можете использовать его без каких-либо итераторов (просто _.map(obj)), если вы просто хотите массив значений. Хорошая часть заключается в том, что если вам нужно какое-то преобразование между ними, вы можете сделать это за один раз.

Пример:

Однако, если вы хотите преобразовать свой объект, вы можете сделать это, даже если вам нужно сохранить ключ, вы можете сделать это ( _.map(obj, (v, k) => {...}) с дополнительным аргументом mapи затем использовать его по своему усмотрению.

Однако существуют другие решения Vanilla JS для этого (так как каждое lodashрешение должно иметь чистую версию JS), например:

  • Object.keysа затем mapих значения
  • Object.values (в ES-2017)
  • Object.entriesа затем mapкаждая пара ключ / значение (в ES-2017)
  • for...in зацикливание и использование каждой клавиши для получения значений

И многое другое. Но поскольку этот вопрос предназначен lodash(и предполагается, что кто-то уже использует его), вам не нужно много думать о версии, поддержке методов и обработке ошибок, если они не найдены.

Существуют и другие решения типа lodash, такие как _.values(более читабельные для конкретных целей), или получение пар, а затем отображение и так далее. но в том случае, если вашему коду требуется гибкость, чтобы вы могли обновлять его в будущем, когда вам нужно keysнемного сохранить или преобразовать значения, тогда лучшим решением будет использование одного, _.mapкак указано в этом ответе. Это будет не так сложно, с точки зрения читабельности.

Кушик Чаттерджи
источник
2
Красиво, очень просто и кратко.
edencorbin
5

Объект для массива

Из всех ответов я думаю, что этот самый лучший:

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

что превращает:

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

чтобы:

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

Массив к объекту

Чтобы преобразовать обратно:

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

Чтобы преобразовать обратно, сохраняя ключ в значении:

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

Дам:

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

В последнем примере вы также можете использовать lodash _.keyBy(arr, 'key')или _.keyBy(arr, i => i.key).

Orad
источник
3

Если вам нужно какое-то пользовательское отображение (например, оригинальный Array.prototype.map) объекта в массив, вы можете просто использовать _.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' }, ... ];

Видеть lodash документ _.forEach https://lodash.com/docs/#forEach

Джил Эпштейн
источник