J'essaie de trouver un moyen efficace et aussi court que possible de réduire les objets presque identiques d'un tableau en objets contenant leurs propres tableaux avec les données non identiques. Cela semble compliqué quand j'essaie de l'expliquer, laissez-moi plutôt vous montrer ce que je veux dire:
J'ai un tableau d'objets qui ressemble à ce qui suit:
...then(data => { let users = []; // gets the correct formatting data.forEach((d, i) => { let found = false; users.forEach((u, j) => { if(d.id === u.id) { u.roles.push({ name:d.rName, authority:d.rAuthority }); u.tokens.push({ id:d.atId, platform:d.atPlatform }); u.profiles.push({ id:d.pId, mobile:d.pMobile }); found = true; } }); if(!found) { users.push({ id:d.id, first_name:d.first_name, email:d.email, roles: [{ name:d.rName, authority:d.rAuthority }], profiles: [{ id:d.pId, mobile:d.pMobile }], tokens: [{ id:d.atId, platform:d.atPlatform }] }); } }); // remove duplicates from sub-arrays users.forEach((user, i) => { user.roles = _.uniqBy(user.roles, 'name'); user.profiles = _.uniqBy(user.profiles, 'id'); user.tokens = _.uniqBy(user.tokens, 'id'); }); });
I veulent transformer ce tableau en un tableau dans lequel les objets avec des identifiants en double sont réduits en un seul objet avec des tableaux d'objets contenant les données non identiques. Cela ressemble à ceci:
[{ id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', roles: [{ name: 'User', authority: 'ROLE_USER' },{ name: 'Admin', authority: 'ROLE_ADMIN' }], profiles: [{ id: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', mobile: '012 345 6789', }], tokens: [{ id: '90db0c5d-3030-44aa-9dc0-40242af0d5c5', platform: 'web', },{ id: 'e7d53cab-a9b9-40ae-9271-11d79c2f269c', platform: 'web', }] }]
Comme vous pouvez le voir, toutes les propriétés du tableau précédent qui avaient un préfixe r
ont maintenant toutes leurs propres objets dans un tableau dans la propriété roles
. Les propriétés préfixées p
sont dans les profils
et les propriétés préfixées à
sont dans les jetons
. Un objet est considéré comme "identique" s'il a le même id
qu'un autre objet.
Voici un code que j'ai écrit qui semble réussir à transformer le premier tableau en second tableau:
[{ id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'User', // 0,1 rAuthority: 'ROLE_USER', // 0,1 pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: '90db0c5d-3030-44aa-9dc0-40242af0d5c5', // 0,2 atPlatform: 'web', },{ id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'User', // 0,1 rAuthority: 'ROLE_USER', // 0,1 pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: 'e7d53cab-a9b9-40ae-9271-11d79c2f269c', // 1,3 atPlatform: 'web', },{ id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'Admin', // 2,3 rAuthority: 'ROLE_ADMIN', // 2,3 pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: '90db0c5d-3030-44aa-9dc0-40242af0d5c5', // 0,2 atPlatform: 'web', },{ id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'Admin', // 2,3 rAuthority: 'ROLE_ADMIN', // 2,3 pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: 'e7d53cab-a9b9-40ae-9271-11d79c2f269c', // 1,3 atPlatform: 'web', }] // I point out which of the properties are not identical by adding // quotes showing which indices of the array contains unique values of // said property. If the there's not a quote to the right of the // property it's identical across all indices.
J'ai deux problèmes avec ce code. La première est qu'il est super long (j'ai en fait supprimé de nombreuses propriétés du premier tableau pour répondre à cette question - en réalité, chaque objet a plus du double du nombre de propriétés que vous voyez ici, ce qui rend ce code beaucoup plus long), et le deuxièmement, je soupçonne fortement que c'est probablement très inefficace.
Question:
Quelqu'un peut-il m'aider à réécrire le code que je ' m en utilisant pour formater mon tableau en quelque chose de plus court et plus efficace. J'ai lodash installé, donc je préfère les réponses qui en ont fait usage, mais je ' J'accepterai aussi volontiers les réponses vanilla.js.
Remarques supplémentaires:
Cette question fait suite à une autre question que j'ai postée. L'examen de cette question vous montrera vaguement d'où proviennent les données que j'essaie de transformer dans cette question. La version courte est qu'elle provient de la base de données, c'est mon idée du chargement paresseux en utilisant Knex.js. L'idée est que chaque utilisateur peut avoir plusieurs rôles, profils et jetons d'authentification.
4 Réponses :
Vous pouvez utiliser un réducteur et créer votre nouveau tableau d'objets:
const input = [{ id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'User', // 0,1 rAuthority: 'ROLE_USER', // 0,1 pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: '90db0c5d-3030-44aa-9dc0-40242af0d5c5', // 0,2 atPlatform: 'web', }, { id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'User', // 0,1 rAuthority: 'ROLE_USER', // 0,1 pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: 'e7d53cab-a9b9-40ae-9271-11d79c2f269c', // 1,3 atPlatform: 'web', }, { id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'Admin', // 2,3 rAuthority: 'ROLE_ADMIN', // 2,3 pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: '90db0c5d-3030-44aa-9dc0-40242af0d5c5', // 0,2 atPlatform: 'web', }, { id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'Admin', // 2,3 rAuthority: 'ROLE_ADMIN', // 2,3 pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: 'e7d53cab-a9b9-40ae-9271-11d79c2f269c', // 1,3 atPlatform: 'web', }]; console.log(input.reduce((acc, val, ind) => { if (!acc.find(el => el.id === val.id)) { acc.push({ id: val.id, first_name: val.first_name, email: val.email, roles: [], profiles: [], tokens: [] }); } else { const el = acc.find(el => el.id === val.id); if (!el.roles.find(a => a.authority === val.rAuthority)) { el.roles.push({ authority: val.rAuthority, name: val.rName }); } if (!el.profiles.find(a => a.id === val.pId)) { el.profiles.push({ id: val.pId, mobile: val.pMobile }); } if (!el.tokens.find(a => a.id === val.atId)) { el.tokens.push({ id: val.atId, platform: val.atPlatform }); } } return acc; }, []));
Une approche légèrement différente de la réponse de quirimmo, utilisant des objets comme valeurs intermédiaires pour mapper chaque élément / sous-élément à son identifiant correspondant, puis en utilisant Object.values
pour les restaurer:
const input = [ {id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'User', rAuthority: 'ROLE_USER', pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: '90db0c5d-3030-44aa-9dc0-40242af0d5c5', atPlatform: 'web'}, {id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'User', rAuthority: 'ROLE_USER', pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: 'e7d53cab-a9b9-40ae-9271-11d79c2f269c', atPlatform: 'web'}, {id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'Admin', rAuthority: 'ROLE_ADMIN', pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: '90db0c5d-3030-44aa-9dc0-40242af0d5c5', atPlatform: 'web'}, {id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'Admin', rAuthority: 'ROLE_ADMIN', pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: 'e7d53cab-a9b9-40ae-9271-11d79c2f269c', atPlatform: 'web'} ]; const result = Object.values(input.reduce((result, item) => { if (!(item.id in result)) { result[item.id] = {id: item.id, first_name: item.first_name, email: item.email, roles: {}, profiles: {}, tokens: {}}; } result[item.id].roles[item.rName] = {name: item.rName, authority: item.rAuthority}; result[item.id].profiles[item.pId] = {id: item.pId, mobile: item.pMobile}; result[item.id].tokens[item.atId] = {id: item.atId, platform: item.atPlatform}; return result; }, {})).map(item => { ['roles', 'profiles', 'tokens'].forEach(prop => item[prop] = Object.values(item[prop])); return item; }); console.log(result);
Fondamentalement :
Array.reduce
transforme le tableau initial en un objet indexé par les identifiants des éléments et contenant des objets rôles / profils / jetons également indexés par leurs identifiants correspondants, Object.values
convertit l'objet obtenu en un tableau, Array.map
appelle Object.values
sur les rôles / profils / jetons de chaque élément pour les transformer en tableaux souhaités. En utilisant lodash, vous pouvez créer une fonction partiellement appliquée qui obtient les propriétés d'un objet en utilisant _.pickBy ()
et une expression régulière avec la chaîne avec laquelle la propriété doit commencer. Ensuite, vous pouvez créer un créateur d'attribut en utilisant la chaîne appropriée ( at
pour tokens
).
Maintenant _.groupBy ()
le id
des éléments, et mappez chaque groupe pour créer l'objet en utilisant les créateurs d'attributs.
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
const data = [{"id":"6b6574cf-d77a-4ed8-852f-cb60a0d377cd","first_name":"SomeName","email":"some@email.com","rName":"User","rAuthority":"ROLE_USER","pId":"e7da65a9-ea2d-4c77-82f6-e1addc78fb6e","pMobile":"012 345 6789","atId":"90db0c5d-3030-44aa-9dc0-40242af0d5c5","atPlatform":"web"},{"id":"6b6574cf-d77a-4ed8-852f-cb60a0d377cd","first_name":"SomeName","email":"some@email.com","rName":"User","rAuthority":"ROLE_USER","pId":"e7da65a9-ea2d-4c77-82f6-e1addc78fb6e","pMobile":"012 345 6789","atId":"e7d53cab-a9b9-40ae-9271-11d79c2f269c","atPlatform":"web"},{"id":"6b6574cf-d77a-4ed8-852f-cb60a0d377cd","first_name":"SomeName","email":"some@email.com","rName":"Admin","rAuthority":"ROLE_ADMIN","pId":"e7da65a9-ea2d-4c77-82f6-e1addc78fb6e","pMobile":"012 345 6789","atId":"90db0c5d-3030-44aa-9dc0-40242af0d5c5","atPlatform":"web"},{"id":"6b6574cf-d77a-4ed8-852f-cb60a0d377cd","first_name":"SomeName","email":"some@email.com","rName":"Admin","rAuthority":"ROLE_ADMIN","pId":"e7da65a9-ea2d-4c77-82f6-e1addc78fb6e","pMobile":"012 345 6789","atId":"e7d53cab-a9b9-40ae-9271-11d79c2f269c","atPlatform":"web"}]; const createAttribute = startStr => { const pattern = new RegExp(`^${startStr}[A-Z]`); return arr => _.uniqWith(_.map(arr, _.flow([ obj => _.pickBy(obj, (v, k) => pattern.test(k)), obj => _.mapKeys(obj, (v, k) => k.replace(/(^[a-z]+)([A-Z].+$)/, '$2') // key name without the prefix .toLowerCase() ) ])), _.isEqual); }; const createRoles = createAttribute('r'); const createProfiles = createAttribute('p'); const createTokens = createAttribute('at'); const fn = _.flow([ arr => _.groupBy(arr, 'id'), groups => _.map(groups, group => { const { id, first_name, email } = _.first(group); return { id, first_name, email, roles: createRoles(group), profiles: createProfiles(group), tokens: createTokens(group) }; }) ]); const result = fn(data); console.log(result);
Vous pouvez prendre des tableaux pour le regroupement souhaité avec leurs clés et leurs alias.
.as-console-wrapper { max-height: 100% !important; top: 0; }
var data = [{ id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'User', rAuthority: 'ROLE_USER', pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: '90db0c5d-3030-44aa-9dc0-40242af0d5c5', atPlatform: 'web' }, { id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'User', rAuthority: 'ROLE_USER', pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: 'e7d53cab-a9b9-40ae-9271-11d79c2f269c', atPlatform: 'web' }, { id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'Admin', rAuthority: 'ROLE_ADMIN', pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: '90db0c5d-3030-44aa-9dc0-40242af0d5c5', atPlatform: 'web' }, { id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd', first_name: 'SomeName', email: 'some@email.com', rName: 'Admin', rAuthority: 'ROLE_ADMIN', pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e', pMobile: '012 345 6789', atId: 'e7d53cab-a9b9-40ae-9271-11d79c2f269c', atPlatform: 'web' }], head = [['id'], ['first_name'], ['email']], sub = [ ['roles', [['name', 'rName'], ['authority', 'rAuthority']]], ['profiles', [['id', 'pId'], ['mobile', 'pMobile']]], ['tokens', [['id', 'atId'], ['platform', 'atPlatform']]] ], result = data.reduce((r, o) => { const mapData = ([key, alias = key]) => ({ [key]: o[alias] }); var temp = r.find(q => q[head[0]] === o[head[0]]); if (!temp) { r.push(temp = Object.assign(...head.map(mapData))); } sub.forEach(([s, keys]) => { temp[s] = temp[s] || []; var inner = temp[s].find(q => q[keys[0][0]] === o[keys[0][1]]); if (!inner) { temp[s].push(Object.assign(...keys.map(mapData))); } }); return r; }, []); console.log(result);