transformar objeto em matriz com lodash

165

Como posso transformar um grande objectem arraylodash?

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
fonte
@Mritunjay Sim, porque os documentos têm uma ótima visão geral da biblioteca ... não. É apenas uma lista exaustiva de funções e passar por cada uma delas pode ser uma perda de tempo, se não houver uma. A questão é justa.
Epirocks 10/03

Respostas:

263

Você pode fazer

var arr = _.values(obj);

Para documentação veja aqui.

Daniel Schmidt
fonte
34
E se você quisesse preservar a chave como uma propriedade? (neste exemplo, se a idpropriedade não existia e que queria criá-la com base na chave de cada objeto.
Michael Liquori
8
Você poderia fazer algo assim:var arr = _.values(_.mapKeys(obj, function(value, key) { value.id = key; return value; }));
Daniel Schmidt
1
@DanielSchmidt Não sei ao certo o que fiz de errado, mas essa amostra retornou apenas 1 linha para mim. :( Então o que eu fiz é empurrar manualmente o returnvalor para uma matriz como este: const divisionsList = []; _.mapKeys(divisions, (value, key) => { divisionsList[key] = value; });Eu apreciaria quaisquer comentários ou sugestões para melhorar esta abordagem.
JohnnyQ
8
@JohnnyQ Eu acho que você precisará usar o mapValues, por exemplo, por exemploconst toArrayWithKey = (obj, keyAs) => _.values(_.mapValues(obj, (value, key) => { value[keyAs] = key; return value; }));
orjan 6/16
1
@orjan Sim, eu realmente descobri isso, só esqueci de atualizar. Obrigado por isso.
JohnnyQ
38
_.toArray(obj);

Saídas como:

[
  {
    "name": "Ivan",
    "id": 12,
    "friends": [
      2,
      44,
      12
    ],
    "works": {
      "books": [],
      "films": []
    }
  },
  {
    "name": "John",
    "id": 22,
    "friends": [
      5,
      31,
      55
    ],
    "works": {
      "books": [],
      "films": []
    }
  }
]"
Jivings
fonte
1
_.toArray () Funciona bem @jivings
Syed Zain Ali
4
para obter apenas valores, é uma boa opção, mas toArraynão há como preservar as chaves, se necessário.
Koushik Chatterjee
33

Uma solução nativa moderna, se alguém estiver interessado:

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

ou (não IE):

const arr = Object.entries(obj).map(([key, value]) => ({ key, value }));
Dominic
fonte
2
porque não bastaObject.keys(obj).map(key=>({key,value: obj[key]}))
Koushik Chatterjee
1
Eu gosto que ele nem usa lodash, muito bem senhor!
HungryPipo
1
@Dominic Agora você mudou sua resposta completa e tirou do meu comentário, mesmo sem uma menção (você editou isso). Bem feito 👏 😁😁
Koushik Chatterjee
1
@KoushikChatterjee adicionou-o de volta
Dominic
2
Isso seria mais útil? const arr = Object.keys(obj).map(id => ({ id, ...obj[id] })); isso traria todo o objeto para os dados retornados não? (usando 'id' desde o consulente originais queria armazenar sua chave como o prop id)
zabaat
20

Para mim, isso funcionou:

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

Acontece

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

para dentro

[{"a":"b"}, {"c":"d"}, {"e":"f"}]
NoNine
fonte
1
Eu precisava transformar um objeto em uma matriz, de forma que cada chave / valor do objeto original fosse um objeto {key: value} na matriz. _.toPairs (data) pega o objeto {"a": "b", "c": "d", "e": "f"} e o retorna como uma matriz de matrizes como [["a": " b "], [" c ":" d "], [" e ":" f "]]. _.fromPairs faz o oposto, pega uma matriz com 2 elementos: ["a", "b"] e a retorna como um objeto: {"a": "b"}. Usando _.map, eu iterava sobre a matriz se matrizes criadas por _.toPairs para transformá-la em uma matriz de objetos com a ajuda de _.fromPairs.
NoNine 23/09
1
Fico feliz que rolei para baixo para ver isso. Sua solução funcionou para mim! Obrigado!
Wale
@NoNine Você não precisa aplicar o mapa em uma matriz (de matriz), pode aplicá-lo diretamente no objeto de entrada e retornar cada par de valores-chave, _.map(data, (v,k)=>({[k]: v}))ver minha resposta para detalhes. _.toPairse _fromPairsé adicional e desnecessário aqui.
Koushik Chatterjee
Não é para isso que a pergunta se destina. porque é um pouco difícil usar o resultado, pois cada entrada contém uma chave (que você não sabe) e, novamente, você precisa passar por alguma lógica (por exemplo, Object.keys ou Object.values) para cada entrada separada para obter o valor de cada, se brinquedo querem preservar as chaves, em seguida, você pode criar uma matriz de objetos que stuctrured como[{key: 'someKey', val: 'The value'}, {....},...]
Koushik Chatterjee
13

Existem algumas maneiras de obter o resultado que você procura. Vamos dividi-los em categorias:

Somente valores ES6 :

O principal método para isso é Object.values . Mas, usando Object.keys e Array.map, você também pode obter o resultado esperado:

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

Chave e valor ES6 :

Usando o mapa e as propriedades / destruição dinâmicas / computadas do ES6, você pode reter a chave e retornar um objeto do mapa.

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

Apenas valores Lodash :

O método projetado para isso é, _.valuesno entanto, existem "atalhos", como _.mapo método utilitário, _.toArrayque também retornaria uma matriz contendo apenas os valores do objeto. Você poderia também _.mapse o _.keyse obter os valores do objeto usando a obj[key]notação.

Nota: _.mapquando passado, um objeto usaria seu baseMapmanipulador, que está basicamente forEachnas propriedades do objeto.

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

Chave e valor Lodash :

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

Observe que nos exemplos acima, o ES6 é usado (funções de seta e propriedades dinâmicas). Você pode usar o lodash _.fromPairse outros métodos para compor um objeto se o ES6 for um problema.

Akrion
fonte
12

Se você deseja que a chave (id neste caso) seja preservada como uma propriedade de cada item da matriz, você pode fazer

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
fonte
8

Atualização de 2017: Object.values , lodash values e toArray fazem isso. E para preservar o mapa de chaves e espalhar o operador, jogue bem:

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

Transformando objeto em matriz com JavaScript simples ( 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);

Se você também quer manter o uso chaves Object.entriese Array#mapcomo isto:

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

Barba Negra
fonte
5

var arr = _.map(obj)

Você também pode usar a _.mapfunção (de ambos lodashe underscore) object, ele manipulará internamente esse caso, iterará sobre cada valor e chave com seu iterado e, finalmente, retornará uma matriz. De fato, você pode usá-lo sem nenhum iterado (apenas _.map(obj)) se quiser apenas uma matriz de valores. A parte boa é que, se você precisar de alguma transformação no meio, poderá fazê-lo de uma só vez.

Exemplo:

No entanto, se você quiser transformar seu objeto, poderá fazê-lo, mesmo que precise preservar a chave, faça isso ( _.map(obj, (v, k) => {...}) com argumentos adicionais mape use-o como desejar.

No entanto, existem outras soluções Vanilla JS para isso (como todas as lodashsoluções devem ter uma versão JS pura), como:

  • Object.keyse então mapeles para valores
  • Object.values (no ES-2017)
  • Object.entriese depois mapcada par de chave / valor (no ES-2017)
  • for...in faça um loop e use cada tecla para encontrar valores

E muito mais. Mas como essa pergunta é para lodash(e assumindo que alguém já a esteja usando), você não precisa pensar muito sobre versão, suporte a métodos e tratamento de erros, se não forem encontrados.

Existem outras soluções Lodash como _.values(mais legíveis para fins específicos), ou obter pares e, em seguida, mapear e assim por diante. mas, se o seu código precisar de flexibilidade, você poderá atualizá-lo no futuro, pois precisará preservar keysou transformar um pouco os valores; a melhor solução é usar um único _.mapcomo endereço nesta resposta. Isso não será tão difícil quanto a legibilidade também.

Koushik Chatterjee
fonte
2
Bom, muito simples e mais conciso.
Edencorbin
5

Objeto para matriz

De todas as respostas, acho que essa é a melhor:

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

que transforma:

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

para:

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

Matriz para objeto

Para transformar de volta:

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

Para transformar novamente mantendo a chave no valor:

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

Darei:

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

Para o último exemplo, você também pode usar lodash _.keyBy(arr, 'key')ou _.keyBy(arr, i => i.key).

orad
fonte
3

Se você deseja algum mapeamento personalizado (como Array.prototype.map original) de Object em uma Matriz, basta usar _.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' }, ... ];

Consulte o lodashdocumento de _.forEach https://lodash.com/docs/#forEach

Gil Epshtain
fonte