javascript - Filtrer objektets egenskaper etter nøkkel i ES6
La oss si at jeg har et objekt:
{
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
}
Jeg vil lage et annet objekt ved å filtrere objektet ovenfor, slik at jeg har noe som.
{
item1: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
}
Jeg leter etter en ryddig måte å oppnå dette på ved å bruke Es6, så spread-operatører er tilgjengelige for meg.
Svar #1
Hvis du har en liste over tillatte verdier, kan du enkelt beholde dem i et objekt ved å bruke:
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);Dette bruker:
Object.keysfor å liste alle egenskaper iraw(de opprinnelige dataene), deretterArray.prototype.filterfor å velge nøkler som er til stede i den tillatte listen, ved å brukeArray.prototype.includesfor å forsikre seg om at de er til stede
Array.prototype.reduce for å bygge et nytt objekt med bare de tillatte egenskapene.Dette vil lage en grunn kopi med de tillatte egenskapene (men vil ikke kopiere egenskapene selv).
Du kan også bruke objektspredningsoperatoren for å lage en serie med objekter uten å endre dem (takk til rjerue for å nevne dette):
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);For formål med trivia, hvis du ønsket å fjerne de uønskede feltene fra de opprinnelige dataene (noe jeg ikke ville anbefale å gjøre, siden det innebærer noen stygge mutasjoner), kunne du invertere includes-sjekken slik:
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);Jeg inkluderer dette eksemplet for å vise en mutasjonsbasert løsning, men jeg anbefaler ikke å bruke den.
Svar #2
Hvis du er ok med å bruke ES6-syntaks, finner jeg at den reneste måten å gjøre dette på, som nevnt her og her, er:
const data = {
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
const { item2, ...newData } = data;
Nå inneholder newData:
{
item1: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
Eller, hvis du har nøkkelen lagret som en streng:
const key = 'item2';
const { [key]: _, ...newData } = data;
I det siste tilfellet blir [key] konvertert til item2, men siden du bruker en const-tilordning, må du spesifisere et navn for tilordningen. _ representerer en verdi som kastes bort.
Mer generelt:
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, ...
Dette reduserer ikke bare operasjonen din til en én-liners, men det krever heller ikke at du vet hva de andre nøklene er (de du ønsker å bevare).
En enkel hjelpefunksjon vil se slik ut:
function removePropFromObject(obj, prop) {
const { [prop]: _, ...rest } = obj
return { ...rest }
}
Svar #3
Du kan nå gjøre det kortere og enklere ved å bruke Object.fromEntries-metoden (sjekk nettleserstøtte):
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)
)
);
les mer om: Object.fromEntries
Svar #4
Ingenting som ikke har blitt sagt før, men for å kombinere noen svar til et generelt ES6-svar:
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);Svar #5
Den reneste måten du kan finne er med 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)
Svar #6
Bare en annen løsning i en linje med moderne JS uten eksterne biblioteker.
Jeg lekte med «Destructuring»-funksjonen :
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);Svar #7
Bygger videre på disse to svarene:
https://stackoverflow.com/a/56081419/13819049
https://stackoverflow.com/a/54976713/13819049
Vi kan gjøre:
const original = { a: 1, b: 2, c: 3 };
const allowed = ['a', 'b'];
const filtered = Object.fromEntries(allowed.map(k => [k, original[k]]));
Hvilken er renere og raskere:
https://jsbench.me/swkv2cbgkd/1
Svar #8
ok, hva med denne enlinjers
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]})));
Svar #9
En annen løsning som bruker Array.reduce-metoden på de tillatte nøklene:
const raw = {
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
const allowed = ['item1', 'item3'];
const filtered = allowed.reduce((obj, key) => {
obj[key] = raw[key];
return obj
}, {})
console.log(filtered);
Spesielt i tilfelle større kildeobjekter (rå i dette eksempelet) vil det gi mening. Iterasjonen vil ikke bli utført ved bruk av alle oppføringene i kilden, men bare ved bruk av nøklene du ønsker å filtrere, og dermed kortere/raskere...
Demonstrasjon i denne Fiddle...
Men jeg må også si at jeg liker løsningen i dette svaret her, som bruker Object.fromEntries, Array.filter og Array.includes:
const object = Object.fromEntries( Object.entries(raw).filter(([key, value]) => allowed.includes(key)) );
Demonstrasjon i denne Fiddle...
Svar #10
Du kan legge til en generell ofilter (implementert med generell oreduce) slik at du enkelt kan filtrere objekter på samme måte som du kan med arrays -
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
)
Vi kan se det fungere her -
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 } } ]
)
Bekreft resultatene i din egen nettleser nedenfor -
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 } } ]
)Disse to funksjonene kan implementeres på mange måter. Jeg valgte å knytte til Array.prototype.reduce inne i oreduce, men du kunne like gjerne skrevet alt fra bunnen av
Svar #11
Svarene her er definitivt passende, men de er litt trege fordi de krever at man må gå gjennom hvitelisten for hver egenskap i objektet. Løsningen nedenfor er mye raskere for store datasett fordi den bare går gjennom hvitelisten én gang:
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,
{}
);
}
const result = sanitize(data, whitelist);
console.log(result);