filter - ejemplo - Filtrar propiedades de objeto por clave en ES6
reduce javascript (19)
Ahora puede hacerlo más corto y simple utilizando el método Object.fromEntries (consulte el soporte del navegador):
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
Leer más sobre: Object.fromEntries
Digamos que tengo un objeto:
{
item1: { key: ''sdfd'', value:''sdfd'' },
item2: { key: ''sdfd'', value:''sdfd'' },
item3: { key: ''sdfd'', value:''sdfd'' }
}
Quiero crear otro objeto filtrando el objeto de arriba, así que tengo algo así.
{
item1: { key: ''sdfd'', value:''sdfd'' },
item3: { key: ''sdfd'', value:''sdfd'' }
}
Estoy buscando una manera limpia de lograr esto usando Es6, por lo que los operadores de propagación están disponibles para mí. ¡Gracias!
Así es como lo hice recientemente:
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]})));
Durante el ciclo, no devuelva nada cuando se encuentren ciertas propiedades / claves y continúe con el resto:
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> ); });
Esta función filtrará un objeto basado en una lista de claves, es más eficiente que la respuesta anterior ya que no tiene que usar Array.filter antes de llamar a reduce. entonces su O (n) en oposición a O (n + filtrado)
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>
);
});
Hay muchas formas de lograr esto. La respuesta aceptada utiliza un enfoque Keys-Filter-Reduce, que no es el más eficaz.
En cambio, usar un
for...in
loop para recorrer las teclas de un objeto, o recorrer las teclas permitidas, y
luego
componer un nuevo objeto es ~ 50% más de rendimiento
a
.
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)));
a. Ver jsPerf para los puntos de referencia de un caso de uso simple. Los resultados diferirán según los navegadores.
La forma más limpia que puedes encontrar es con 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)
Las respuestas aquí son definitivamente adecuadas, pero son un poco lentas porque requieren recorrer la lista blanca para cada propiedad del objeto. La solución a continuación es mucho más rápida para grandes conjuntos de datos porque solo recorre la lista blanca una vez:
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)
Nada que no se haya dicho antes, pero para combinar algunas respuestas a una respuesta general de 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);
Piggybacking en la respuesta de ssube .
Aquí hay una versión reutilizable.
Object.filterByKey = function (obj, predicate) {
return Object.keys(obj)
.filter(key => predicate(key))
.reduce((out, key) => {
out[key] = obj[key];
return out;
}, {});
}
Para llamarlo use
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);
Lo bueno de las funciones de flecha de ES6 es que no tiene que pasar
allowed
como parámetro.
Puede agregar un
ofilter
genérico (implementado con material genérico) para que pueda filtrar fácilmente los objetos de la misma manera que puede hacer arreglos:
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
)
Podemos verlo trabajando aquí.
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 } } ]
)
Verifique los resultados en su propio navegador a continuación:
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 } } ]
)
Estas dos funciones podrían implementarse de muchas maneras.
Elegí adjuntar a
Array.prototype.reduce
dentro de
oreduce
pero podría escribirlo todo desde cero
Puedes eliminar una clave específica de tu objeto
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;
Puedes hacer algo como esto:
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);
Esto funciona pero no está muy claro, además de que no se recomienda la declaración
with
(
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with
).
Se puede lograr una solución más simple sin usar
filter
con
Object.entries()
lugar 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
},{})
Si está de acuerdo con el uso de la sintaxis de ES6, creo que la forma más limpia de hacerlo, como se señala here y here es:
const data = {
item1: { key: ''sdfd'', value:''sdfd'' },
item2: { key: ''sdfd'', value:''sdfd'' },
item3: { key: ''sdfd'', value:''sdfd'' }
};
const { item2, ...newData } = data;
Ahora,
newData
contiene:
{
item1: { key: ''sdfd'', value:''sdfd'' },
item3: { key: ''sdfd'', value:''sdfd'' }
};
O, si tiene la clave almacenada como una cadena:
const key = ''item2'';
const { [key]: _, ...newData } = data;
En el último caso,
[key]
se convierte en
item2
pero dado que está utilizando una asignación
const
, debe especificar un nombre para la asignación.
_
representa un valor de descarte.
Más generalmente:
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, ...
Esto no solo reduce su operación a una sola línea, sino que tampoco requiere que sepa cuáles son las otras claves (las que desea conservar).
Si tiene una lista de valores permitidos, puede retenerlos fácilmente en un objeto usando:
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);
Esto usa:
-
Object.keys
para enumerar todas las propiedades enraw
(los datos originales), luego -
Array.prototype.filter
para seleccionar las claves que están presentes en la lista permitida, utilizando-
Array.prototype.includes
para asegurarse de que estén presentes
-
-
Array.prototype.reduce
para construir un nuevo objeto con solo las propiedades permitidas.
Esto hará una copia superficial con las propiedades permitidas (pero no copiará las propiedades en sí).
También puede usar el operador de propagación de objetos para crear una serie de objetos sin mutarlos (gracias a rjerue por mencionar esto ):
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);
Para fines de trivia, si desea eliminar los campos no deseados de los datos originales (lo que no recomendaría hacer, ya que implica algunas mutaciones feas), puede invertir la verificación de inclusiones de la siguiente manera:
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);
Incluyo este ejemplo para mostrar una solución basada en la mutación, pero no sugiero usarla.
Solo otra solución en una línea de código .
Estaba jugando con la función " Destructuring ":
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);
ok, ¿qué tal este one-liner
const dummyObj = Object.assign({}, obj);
delete dummyObj[key];
const target = Object.assign({}, {...dummyObj});
Bien, ¿qué tal esto?
filteredObject(myData, [''item2'']); //{item1: { key: ''sdfd'', value:''sdfd'' }, item3: { key: ''sdfd'', value:''sdfd'' }}
y llámalo así:
function filterObjectByKeys (object, keys) {
return Object.keys(object).reduce((accum, key) => {
if (keys.includes(key)) {
return { ...accum, [key]: object[key] }
} else {
return accum
}
}, {})
}
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;
}