[英]Filter object properties by key in ES6
假设我有一个对象:
{
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
}
我想通过过滤上面的对象来创建另一个对象,所以我有类似的东西。
{
item1: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
}
我正在寻找一种使用 Es6 完成此操作的干净方法,因此我可以使用扩展运算符。
如果您有一个允许值列表,您可以使用以下方法轻松地将它们保留在对象中:
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);
这使用:
Object.keys
列出的所有属性raw
(原始数据),然后Array.prototype.filter
选择存在于允许列表中的键,使用
Array.prototype.includes
以确保它们存在Array.prototype.reduce
以仅使用允许的属性构建新对象。这将使用允许的属性进行浅拷贝(但不会复制属性本身)。
您还可以使用对象扩展运算符来创建一系列对象而不改变它们(感谢rjerue 提到这一点):
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);
出于琐事的目的,如果您想从原始数据中删除不需要的字段(我不建议这样做,因为它涉及一些丑陋的突变),您可以像这样反转includes
检查:
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);
我包含这个例子是为了展示一个基于突变的解决方案,但我不建议使用它。
如果你都OK使用ES6语法,我发现,最干净的方式来做到这一点,因为注意到这里和这里是:
const data = {
item1: { key: 'sdfd', value:'sdfd' },
item2: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
const { item2, ...newData } = data;
现在, newData
包含:
{
item1: { key: 'sdfd', value:'sdfd' },
item3: { key: 'sdfd', value:'sdfd' }
};
或者,如果您将密钥存储为字符串:
const key = 'item2';
const { [key]: _, ...newData } = data;
在后一种情况下, [key]
被转换为item2
但由于您使用的是const
分配,因此您需要为分配指定一个名称。 _
表示丢弃值。
更普遍:
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, ...
这不仅将您的操作简化为单行操作,而且还不需要您知道其他键是什么(您想要保留的键)。
一个简单的效用函数如下所示:
function removePropFromObject(obj, prop) {
const { [prop]: _, ...rest } = obj
return { ...rest }
}
你能找到的最干净的方法是使用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)
没有什么之前没有说过,但结合一般 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);
您现在可以使用Object.fromEntries方法使其更短更简单(检查浏览器支持):
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)
)
);
阅读更多关于: Object.fromEntries
只是现代 JS 一行中的另一种解决方案,没有外部库。
我正在玩“解构”功能:
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);
好的,这个单线怎么样
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]})));
你可以添加一个通用的ofilter
(用通用的oreduce
实现),这样你就可以像处理数组一样轻松地过滤对象——
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 } } ]
)
在以下您自己的浏览器中验证结果 -
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 } } ] )
这两个功能可以通过多种方式实现。 我选择在oreduce
附加到Array.prototype.reduce
但你也可以很容易地从头开始写
在允许的键上使用Array.reduce
方法的另一种解决方案:
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);
特别是在较大的源对象(在本例中为原始对象)的情况下,这将是有意义的。 不会使用源的所有条目执行迭代,而只会使用要过滤的键,因此更短/更快......
但我不得不说我也喜欢这个答案中的解决方案,它使用Object.fromEntries
Array.filter
和Array.includes
:
const object = Object.fromEntries( Object.entries(raw).filter(([key, value]) => allowed.includes(key)) );
我最近是这样做的:
const dummyObj = Object.assign({}, obj);
delete dummyObj[key];
const target = Object.assign({}, {...dummyObj});
这里的答案绝对合适,但它们有点慢,因为它们需要遍历对象中每个属性的白名单。 对于大型数据集,下面的解决方案要快得多,因为它只循环访问白名单一次:
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);
使用Object.entries()
而不是Object.keys()
可以实现不使用filter
更简单的解决方案
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
},{})
捎带ssube 的回答。
这是一个可重复使用的版本。
Object.filterByKey = function (obj, predicate) {
return Object.keys(obj)
.filter(key => predicate(key))
.reduce((out, key) => {
out[key] = obj[key];
return out;
}, {});
}
调用它使用
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);
ES6 箭头函数的美妙之处在于您不必将allowed
作为参数传入。
简单的方法! 去做这个。
const myData = { item1: { key: 'sdfd', value:'sdfd' }, item2: { key: 'sdfd', value:'sdfd' }, item3: { key: 'sdfd', value:'sdfd' } }; const{item1,item3}=myData const result =({item1,item3})
你可以这样做:
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);
这有效但不是很清楚,另外不推荐with
语句( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with )。
我知道这已经有很多答案了,这是一个相当古老的问题。 但我只是想出了这个简洁的单行:
JSON.parse(JSON.stringify(raw, ['key', 'value', 'item1', 'item3']))
这将返回另一个仅具有白名单属性的对象。 请注意, key
和value
包含在列表中。
有很多方法可以实现这一点。 接受的答案使用 Keys-Filter-Reduce 方法,这不是最高效的。
取而代之的是,使用for...in
通过的物体的键循环来循环,或通过允许键循环,然后构成一个新的对象是〜50%更好的性能一个。
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
一种。 有关简单用例的基准测试,请参阅jsPerf 。 结果会因浏览器而异。
const filteredObject = Object.fromEntries(Object.entries(originalObject).filter(([key, value]) => key !== uuid))
您可以删除对象上的特定属性
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;
我很惊讶怎么还没有人提出这个建议。 它非常干净并且非常明确地说明了您要保留哪些键。
const unfilteredObj = {a: ..., b:..., c:..., x:..., y:...}
const filterObject = ({a,b,c}) => ({a,b,c})
const filteredObject = filterObject(unfilteredObject)
或者,如果您想要一个脏的单衬:
const unfilteredObj = {a: ..., b:..., c:..., x:..., y:...}
const filteredObject = (({a,b,c})=>({a,b,c}))(unfilteredObject);
另一个捷径
function filterByKey(v,keys){ const newObj ={}; keys.forEach(key=>{v[key]?newObj[key]=v[key]:''}); return newObj; } //given let obj ={ foo: "bar", baz: 42,baz2:"blabla" , "spider":"man", monkey:true}; //when let outObj =filterByKey(obj,["bar","baz2","monkey"]); //then console.log(outObj); //{ // "baz2": "blabla", // "monkey": true //}
上述许多解决方案对raw
每个键重复调用Array.prototype.includes
,这将使解决方案 O(n·m) (其中 n 是对象中的键数,m 是允许列表的长度) .
这可以通过使用允许的 Set 来避免,但迭代allowed
键并将它们复制到初始为空的对象会给出非常简单、可读的代码,即 O(m):
const raw = { item1: { key: 'sdfd', value:'sdfd' }, item2: { key: 'sdfd', value:'sdfd' }, item3: { key: 'sdfd', value:'sdfd' } }; const allowed = ['item1', 'item3']; const filtered = {}; for (const key of allowed) { if (key in raw) filtered[key] = raw[key]; } console.log(filtered);
如果您想避免复制继承的属性,您也可以使用raw.hasOwnProperty(key)
而不是key in raw
。
好的,这个怎么样:
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;
}
并这样称呼它:
filteredObject(myData, ['item2']); //{item1: { key: 'sdfd', value:'sdfd' }, item3: { key: 'sdfd', value:'sdfd' }}
此函数将根据键列表过滤对象,它比之前的答案更有效,因为它在调用 reduce 之前不必使用 Array.filter。 所以它的 O(n) 而不是 O(n + 过滤)
function filterObjectByKeys (object, keys) {
return Object.keys(object).reduce((accum, key) => {
if (keys.includes(key)) {
return { ...accum, [key]: object[key] }
} else {
return accum
}
}, {})
}
以下方法采用要过滤掉的对象和任何属性。
function removeObjectKeys(obj, ...keysToRemove) { let mObject = { ...obj } for (let key of keysToRemove) { const { [String(key)]: _, ...rest } = mObject mObject = { ...rest } } return mObject } const obj = { 123: "hello", 345: "world", 567: "and kitty" }; const filtered = removeObjectKeys(obj, 123); console.log(filtered); const twoFiltered = removeObjectKeys(obj, 345, 567); console.log(twoFiltered);
基于这两个答案:
https://stackoverflow.com/a/56081419/13819049
https://stackoverflow.com/a/54976713/13819049
我们可以做的:
const original = { a: 1, b: 2, c: 3 };
const allowed = ['a', 'b'];
const filtered = Object.fromEntries(allowed.map(k => [k, original[k]]));
哪个更干净更快:
在循环期间,当遇到某些属性/键时不返回任何内容并继续其余的:
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>
);
});
另一种方法是使用Array.prototype.forEach()
作为
const raw = { item1: { key: 'sdfd', value: 'sdfd' }, item2: { key: 'sdfd', value: 'sdfd' }, item3: { key: 'sdfd', value: 'sdfd' } }; const allowed = ['item1', 'item3', 'lll']; var finalObj = {}; allowed.forEach(allowedVal => { if (raw[allowedVal]) finalObj[allowedVal] = raw[allowedVal] }) console.log(finalObj)
它仅包含原始数据中可用的那些键的值,从而防止添加任何垃圾数据。
那将是我的解决方案:
const filterObject = (obj, condition) => {
const filteredObj = {};
Object.keys(obj).map(key => {
if (condition(key)) {
dataFiltered[key] = obj[key];
}
});
return filteredObj;
}
使用PropPick包
pick('item1 item3', obj);
// {
// item1: { key: 'sdfd', value:'sdfd' },
// item3: { key: 'sdfd', value:'sdfd' }
// }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.