Disons que j'ai un objet:
{
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
}
Je veux créer un autre objet en filtrant l'objet ci-dessus afin d'avoir quelque chose comme.
{
item1: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
}
Je suis à la recherche d'un moyen propre de réaliser cela en utilisant Es6, afin que les opérateurs de spread soient disponibles pour moi.
Si vous avez une liste de valeurs autorisées, vous pouvez facilement les conserver dans un objet en utilisant:
const raw = {
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
const allowed = ['item1', 'item3'];
const filtered = Object.keys(raw)
.filter(key => allowed.includes(key))
.reduce((obj, key) => {
obj[key] = raw[key];
return obj;
}, {});
console.log(filtered);
Cela utilise:
Object.keys
pour lister toutes les propriétés dans raw
(les données d'origine), puisArray.prototype.filter
pour sélectionner les clés présentes dans la liste des permis, à l'aide de Array.prototype.includes
pour s'assurer de leur présenceArray.prototype.reduce
pour construire un nouvel objet avec uniquement les propriétés autorisées.Cela fera une copie superficielle avec les propriétés autorisées (mais ne copiera pas les propriétés elles-mêmes).
Vous pouvez également utiliser l'opérateur de propagation d'objet pour créer une série d'objets sans les transformer (grâce à rjerue pour avoir mentionné ceci ):
const raw = {
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
const allowed = ['item1', 'item3'];
const filtered = Object.keys(raw)
.filter(key => allowed.includes(key))
.reduce((obj, key) => {
return {
...obj,
[key]: raw[key]
};
}, {});
console.log(filtered);
Si vous voulez supprimer les champs non désirés des données d'origine (ce que je ne voudrais pas recommander de faire, car cela implique des mutations laides), vous pouvez inverser le contrôle includes
de la manière suivante:
const raw = {
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
const allowed = ['item1', 'item3'];
Object.keys(raw)
.filter(key => !allowed.includes(key))
.forEach(key => delete raw[key]);
console.log(raw);
J'inclus cet exemple pour montrer une solution basée sur la mutation, mais je ne suggère pas de l'utiliser.
Si vous êtes d'accord avec l'utilisation de la syntaxe ES6, je trouve que le moyen le plus propre de le faire, comme indiqué par ici et ici est:
const data = {
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
const { item2, ...newData } = data;
Maintenant, newData
contient:
{
item1: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
Ou, si vous avez la clé stockée sous forme de chaîne:
const key = 'item2';
const { [key]: _, ...newData } = data;
Dans ce dernier cas, [key]
est converti en item2
, mais comme vous utilisez une affectation const
, vous devez spécifier un nom pour l'affectation. _
représente une valeur à jeter.
Plus généralement:
const { item2, ...newData } = data; // Assign item2 to item2
const { item2: someVarName, ...newData } = data; // Assign item2 to someVarName
const { item2: _, ...newData } = data; // Assign item2 to _
const { ['item2']: _, ...newData } = data; // Convert string to key first, ...
Non seulement cela réduit votre opération à une ligne, mais vous n’avez pas besoin de savoir quelles sont les autres clés (celles que vous souhaitez conserver).
La manière la plus propre que vous puissiez trouver est avec Lodash # pick
const _ = require('lodash');
const allowed = ['item1', 'item3'];
const obj = {
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
}
const filteredObj = _.pick(obj, allowed)
Rien qui n'ait été dit auparavant, si ce n'est combiner quelques réponses à une réponse générale ES6:
const raw = {
item1: { key: 'sdfd', value: 'sdfd' },
item2: { key: 'sdfd', value: 'sdfd' },
item3: { key: 'sdfd', value: 'sdfd' }
};
const filteredKeys = ['item1', 'item3'];
const filtered = filteredKeys
.reduce((obj, key) => ({ ...obj, [key]: raw[key] }), {});
console.log(filtered);
Juste une autre solution dans une ligne de code .
Je jouais avec " Destructuring " feature:
const raw = {
item1: { key: 'sdfd', value: 'sdfd' },
item2: { key: 'sdfd', value: 'sdfd' },
item3: { key: 'sdfd', value: 'sdfd' }
};
var myNewRaw = (({ item1, item3}) => ({ item1, item3 }))(raw);
console.log(myNewRaw);
Vous pouvez ajouter une ofilter
générique (implémentée avec oreduce
générique) afin de pouvoir facilement filtrer les objets de la même manière que vous pouvez utiliser des tableaux -
const oreduce = (f, acc, o) =>
Object
.entries (o)
.reduce
( (acc, [ k, v ]) => f (acc, v, k, o)
, acc
)
const ofilter = (f, o) =>
oreduce
( (acc, v, k, o)=>
f (v, k, o)
? Object.assign (acc, {[k]: v})
: acc
, {}
, o
)
Nous pouvons le voir fonctionner ici -
const data =
{ item1: { key: 'a', value: 1 }
, item2: { key: 'b', value: 2 }
, item3: { key: 'c', value: 3 }
}
console.log
( ofilter
( (v, k) => k !== 'item2'
, data
)
// [ { item1: { key: 'a', value: 1 } }
// , { item3: { key: 'c', value: 3 } }
// ]
, ofilter
( x => x.value === 3
, data
)
// [ { item3: { key: 'c', value: 3 } } ]
)
Vérifiez les résultats dans votre propre navigateur ci-dessous -
const oreduce = (f, acc, o) =>
Object
.entries (o)
.reduce
( (acc, [ k, v ]) => f (acc, v, k, o)
, acc
)
const ofilter = (f, o) =>
oreduce
( (acc, v, k, o)=>
f (v, k, o)
? Object.assign (acc, { [k]: v })
: acc
, {}
, o
)
const data =
{ item1: { key: 'a', value: 1 }
, item2: { key: 'b', value: 2 }
, item3: { key: 'c', value: 3 }
}
console.log
( ofilter
( (v, k) => k !== 'item2'
, data
)
// [ { item1: { key: 'a', value: 1 } }
// , { item3: { key: 'c', value: 3 } }
// ]
, ofilter
( x => x.value === 3
, data
)
// [ { item3: { key: 'c', value: 3 } } ]
)
Ces deux fonctions pourraient être mises en œuvre de plusieurs manières. J'ai choisi d'attacher à Array.prototype.reduce
dans oreduce
mais vous pouvez tout aussi facilement tout écrire à partir de zéro
Voici comment je l'ai fait, récemment:
const dummyObj = Object.assign({}, obj);
delete dummyObj[key];
const target = Object.assign({}, {...dummyObj});
Piggybacking sur la réponse de ssube .
Voici une version réutilisable.
Object.filterByKey = function (obj, predicate) {
return Object.keys(obj)
.filter(key => predicate(key))
.reduce((out, key) => {
out[key] = obj[key];
return out;
}, {});
}
Pour l'appeler utilisez
const raw = {
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
const allowed = ['item1', 'item3'];
var filtered = Object.filterByKey(raw, key =>
return allowed.includes(key));
});
console.log(filtered);
La belle chose à propos des fonctions fléchées de ES6 est qu'il n'est pas nécessaire de passer allowed
en tant que paramètre.
ok, que diriez-vous de cette ligne
const raw = {
item1: { key: 'sdfd', value: 'sdfd' },
item2: { key: 'sdfd', value: 'sdfd' },
item3: { key: 'sdfd', value: 'sdfd' }
};
const filteredKeys = ['item1', 'item3'];
const filtered = Object.assign({}, ...filteredKeys.map(key=> ({[key]:raw[key]})));
Vous pouvez faire quelque chose comme ça:
const base = {
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
const filtered = (
source => {
with(source){
return {item1, item3}
}
}
)(base);
// one line
const filtered = (source => { with(source){ return {item1, item3} } })(base);
Cela fonctionne, mais n'est pas très clair. En outre, l'instruction with
n'est pas recommandée ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with ).
Une solution plus simple sans utiliser filter
peut être obtenue avec Object.entries()
au lieu de Object.keys()
const raw = {
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
const allowed = ['item1', 'item3'];
const filtered = Object.entries(raw).reduce((acc,Elm)=>{
const [k,v] = Elm
if (allowed.includes(k)) {
acc[k] = v
}
return acc
},{})
Les réponses ici sont certainement appropriées, mais elles sont un peu lentes car elles nécessitent la lecture en boucle de la liste blanche pour chaque propriété de l'objet. La solution ci-dessous est beaucoup plus rapide pour les grands ensembles de données car elle ne parcourt qu'une fois la liste blanche:
const data = {
allowed1: 'blah',
allowed2: 'blah blah',
notAllowed: 'woah',
superSensitiveInfo: 'whooooah',
allowed3: 'bleh'
};
const whitelist = ['allowed1', 'allowed2', 'allowed3'];
function sanitize(data, whitelist) {
return whitelist.reduce(
(result, key) =>
data[key] !== undefined
? Object.assign(result, { [key]: data[key] })
: result,
{}
);
}
sanitize(data, whitelist)
Vous pouvez maintenant le rendre plus court et plus simple en utilisant la méthodeObject.fromEntries(vérifiez la prise en charge du navigateur):
const raw = { item1: { prop:'1' }, item2: { prop:'2' }, item3: { prop:'3' } };
const allowed = ['item1', 'item3'];
const filtered = Object.fromEntries(Object.entries(raw).filter(([key, val])=>allowed.includes(key)));
en savoir plus sur: Object.fromEntries
OK, que diriez-vous de ceci:
const myData = {
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
function filteredObject(obj, filter) {
if(!Array.isArray(filter)) {
filter = [filter.toString()];
}
const newObj = {};
for(i in obj) {
if(!filter.includes(i)) {
newObj[i] = obj[i];
}
}
return newObj;
}
et appelez ça comme ça:
filteredObject(myData, ['item2']); //{item1: { key: 'sdfd', value:'sdfd' }, item3: { key: 'sdfd', value:'sdfd' }}
Pendant la boucle, ne retourne rien lorsque certaines propriétés/clés sont rencontrées et continue avec le reste:
const loop = product =>
Object.keys(product).map(key => {
if (key === "_id" || key === "__v") {
return;
}
return (
<ul className="list-group">
<li>
{product[key]}
<span>
{key}
</span>
</li>
</ul>
);
});
Cette fonction va filtrer un objet en fonction d'une liste de clés, ce qui est plus efficace que la réponse précédente car il n'est pas nécessaire d'utiliser Array.filter avant d'appeler réduire. donc son O(n) par opposition à O (n + filtré)
function filterObjectByKeys (object, keys) {
return Object.keys(object).reduce((accum, key) => {
if (keys.includes(key)) {
return { ...accum, [key]: object[key] }
} else {
return accum
}
}, {})
}
Vous pouvez supprimer une clé spécifique sur votre objet
items={
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
}
// Example 1
var key = "item2";
delete items[key];
// Example 2
delete items["item2"];
// Example 3
delete items.item2;
Il y a plusieurs façons d'accomplir ceci. Le réponse acceptée utilise une approche Keys-Filter-Réduire, qui n’est pas la plus performante.
Utiliser plutôt une boucle for...in
pour parcourir les clés d'un objet ou les clés autorisées, et then composer un nouvel objet est environ 50% plus performantune.
const obj = {
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
const keys = ['item1', 'item3'];
function keysReduce (obj, keys) {
return keys.reduce((acc, key) => {
if(obj[key] !== undefined) {
acc[key] = obj[key];
}
return acc;
}, {});
};
function forInCompose (obj, keys) {
const returnObj = {};
for (const key in obj) {
if(keys.includes(key)) {
returnObj[key] = obj[key]
}
};
return returnObj;
};
keysReduce(obj, keys); // Faster if the list of allowed keys are short
forInCompose(obj, keys); // Faster if the number of object properties are low
une. Voir jsPerf pour les points de repère d'un cas d'utilisation simple. Les résultats seront différents selon les navigateurs.