如何有效地过滤对象的对象?
How to filter an object of objects efficiently?
这个问题在SO里被提了很多次,但是都是指一个对象数组。
就我而言,我想过滤一个对象的对象。
假设我有这个对象:
"Users": {
"w14FKo72BieZwbxwUouTpN7UQm02": {
"name": "Naseebullah Ahmadi",
"userType": "Patient",
"writePermission": false
},
"SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
"name": "Levi Yeager",
"userType": "Patient",
"writePermission": false
},
"VoxHFgUEIwRFWg7JTKNXSSoFoMV2": {
"name": "Ernest Kamavuako",
"userType": "Doctor",
"writePermission": true
},
"hFoWuyxv6Vbt8sEKA87T0720tXV2": {
"name": "Karla Stanlee",
"userType": "Doctor",
"writePermission": true
}
}
我想对此进行过滤,以便获得以下内容:
"UsersCustom": {
"w14FKo72BieZwbxwUouTpN7UQm02": {
"name": "Naseebullah Ahmadi",
"userType": "Patient",
"writePermission": false
},
"SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
"name": "Levi Yeager",
"userType": "Patient",
"writePermission": false
}
}
这样做有什么意义?
请注意,这个对象 "User" 在现实中非常庞大(超过 1000 个条目)并且每个用户拥有的属性比单纯的 "name"、"userType" 和 "writePermission" 更多。
我需要过滤用户对象的原因是这样我就可以得到只有 (Patient) 的用户并得到那个 Patient 的 id 在另一个对象中查找最后将它们全部合并到一个对象中。
到目前为止我有什么
// user is the object as seen above
let Patients = users ? (
// I loop through them
Object.keys(users).map((uid, i) => {
// get individual patient
const patient = users[uid];
// check their userType
if (patient.userType === "Patient") {
let customPatient = {
uid: uid,
name: patient.name,
profession: patient.profession,
history: null,
ecg: null,
heartSound: null
};
this._healthRef(uid).then(health => {
customPatient.history = health;
return this._heartSoundRef(uid).then(HS => HS);
}).then(HS => {
customPatient.heartSound = HS;
return this._ecgRef(uid).then(a => a);
}).then(ecg => {
customPatient.ecg = ecg;
}).then(() => {
cusomPatients.push(customPatient);
})
}
})
)
我上面的解决方案虽然部分完成,但仍然效率低下且错误。因为我需要每个患者的 Id 进行其他查找
更新
目前,大多数解决方案都提供循环遍历条目,这意味着在最坏的情况下它将 运行 O(n)。有没有可能比O(n)更快地解决?
您可以使用 for-in
或 Object.keys
或(在现代 JavaScript 引擎上)Object.entries
.
解决此问题
for-in
提供了一种遍历对象的可枚举属性的方法;然后您可以使用这些 属性 名称来查找值:
var result = {};
for (var key in users) {
var entry = users[key];
if (entry.userType === "Patient") {
result[key] = entry;
}
}
实例:
var users = {
"w14FKo72BieZwbxwUouTpN7UQm02": {
"name": "Naseebullah Ahmadi",
"userType": "Patient",
"writePermission": false
},
"SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
"name": "Levi Yeager",
"userType": "Patient",
"writePermission": false
},
"VoxHFgUEIwRFWg7JTKNXSSoFoMV2": {
"name": "Ernest Kamavuako",
"userType": "Doctor",
"writePermission": true
},
"hFoWuyxv6Vbt8sEKA87T0720tXV2": {
"name": "Karla Stanlee",
"userType": "Doctor",
"writePermission": true
}
};
var result = {};
for (var key in users) {
var entry = users[key];
if (entry.userType === "Patient") {
result[key] = entry;
}
}
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
Object.keys
为您提供对象的 own 可枚举属性的数组,因此:
var result = {};
Object.keys(users).forEach(function(key) {
var entry = users[key];
if (entry.userType === "Patient") {
result[key] = entry;
}
});
实例:
var users = {
"w14FKo72BieZwbxwUouTpN7UQm02": {
"name": "Naseebullah Ahmadi",
"userType": "Patient",
"writePermission": false
},
"SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
"name": "Levi Yeager",
"userType": "Patient",
"writePermission": false
},
"VoxHFgUEIwRFWg7JTKNXSSoFoMV2": {
"name": "Ernest Kamavuako",
"userType": "Doctor",
"writePermission": true
},
"hFoWuyxv6Vbt8sEKA87T0720tXV2": {
"name": "Karla Stanlee",
"userType": "Doctor",
"writePermission": true
}
};
var result = {};
Object.keys(users).forEach(function(key) {
var entry = users[key];
if (entry.userType === "Patient") {
result[key] = entry;
}
});
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
Object.entries
提供了一个可迭代对象,它由每个自己的名称和值组成,可枚举 属性。这是很新的。因此,例如(在 ES2015+ 语法中,ES2017 中添加了 Object.entries
但可以填充):
const result = {};
for (const [key, value] of Object.entries(users)) {
if (value.userType === "Patient") {
result[key] = value;
}
}
实例:
const users = {
"w14FKo72BieZwbxwUouTpN7UQm02": {
"name": "Naseebullah Ahmadi",
"userType": "Patient",
"writePermission": false
},
"SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
"name": "Levi Yeager",
"userType": "Patient",
"writePermission": false
},
"VoxHFgUEIwRFWg7JTKNXSSoFoMV2": {
"name": "Ernest Kamavuako",
"userType": "Doctor",
"writePermission": true
},
"hFoWuyxv6Vbt8sEKA87T0720tXV2": {
"name": "Karla Stanlee",
"userType": "Doctor",
"writePermission": true
}
};
const result = {};
for (const [key, value] of Object.entries(users)) {
if (value.userType === "Patient") {
result[key] = value;
}
}
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
您可以在对象键上使用 reduce()
方法并从中构建新对象。
const obj = {"Users":{"w14FKo72BieZwbxwUouTpN7UQm02":{"name":"Naseebullah Ahmadi","userType":"Patient","writePermission":false},"SXMrXfBvexQUXfnVg5WWVwsKjpD2":{"name":"Levi Yeager","userType":"Patient","writePermission":false},"VoxHFgUEIwRFWg7JTKNXSSoFoMV2":{"name":"Ernest Kamavuako","userType":"Doctor","writePermission":true},"hFoWuyxv6Vbt8sEKA87T0720tXV2":{"name":"Karla Stanlee","userType":"Doctor","writePermission":true}}}
const newObj = {
'UserCustom': Object.keys(obj.Users).reduce((r, k) => {
if(obj.Users[k].userType == 'Patient') r[k] = Object.assign({}, obj.Users[k])
return r;
}, {})
}
console.log(newObj)
使用 for...in
遍历对象并检查用户类型是否为 patient。
var users = {
"Users": {
"w14FKo72BieZwbxwUouTpN7UQm02": {
"name": "Naseebullah Ahmadi",
"userType": "Patient",
"writePermission": false
},
"SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
"name": "Levi Yeager",
"userType": "Patient",
"writePermission": false
},
"VoxHFgUEIwRFWg7JTKNXSSoFoMV2": {
"name": "Ernest Kamavuako",
"userType": "Doctor",
"writePermission": true
},
"hFoWuyxv6Vbt8sEKA87T0720tXV2": {
"name": "Karla Stanlee",
"userType": "Doctor",
"writePermission": true
}
}
};
for(let user in users.Users){
if(users.Users.hasOwnProperty(user) && users.Users[user].userType!=="Patient")
delete users.Users[user];
}
console.log(users);
这将修改对象,如果您想保留它,只需对原始对象执行 deep copy。
我的猜测是在解析过程中进行过滤可能是最有效的(还没有 measured/compaed):
j = '{"w14FKo72BieZwbxwUouTpN7UQm02":{"name":"Naseebullah Ahmadi","userType":"Patient","writePermission":false},"SXMrXfBvexQUXfnVg5WWVwsKjpD2":{"name":"Levi Yeager","userType":"Patient","writePermission":false},"VoxHFgUEIwRFWg7JTKNXSSoFoMV2":{"name":"Ernest Kamavuako","userType":"Doctor","writePermission":true},"hFoWuyxv6Vbt8sEKA87T0720tXV2":{"name":"Karla Stanlee","userType":"Doctor","writePermission":true}}'
o = JSON.parse(j, (k, v) => !v.userType || v.userType === 'Patient' ? v : void 0)
console.log(o)
缓存过滤后的对象会更有效地减少网络流量。
使用reduce
方法你可以得到你的对象
var data = {
"w14FKo72BieZwbxwUouTpN7UQm02": {
"name": "Naseebullah Ahmadi",
"userType": "Patient",
"writePermission": false
},
"SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
"name": "Levi Yeager",
"userType": "Patient",
"writePermission": false
},
"VoxHFgUEIwRFWg7JTKNXSSoFoMV2": {
"name": "Ernest Kamavuako",
"userType": "Doctor",
"writePermission": true
},
"hFoWuyxv6Vbt8sEKA87T0720tXV2": {
"name": "Karla Stanlee",
"userType": "Doctor",
"writePermission": true
}
};
var results = Object.keys(data).reduce(function(acc, val) {
if(data[val].userType === 'Patient') acc[val] = data[val];
return acc;
}, {});
console.log(results);
这个问题在SO里被提了很多次,但是都是指一个对象数组。
就我而言,我想过滤一个对象的对象。
假设我有这个对象:
"Users": {
"w14FKo72BieZwbxwUouTpN7UQm02": {
"name": "Naseebullah Ahmadi",
"userType": "Patient",
"writePermission": false
},
"SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
"name": "Levi Yeager",
"userType": "Patient",
"writePermission": false
},
"VoxHFgUEIwRFWg7JTKNXSSoFoMV2": {
"name": "Ernest Kamavuako",
"userType": "Doctor",
"writePermission": true
},
"hFoWuyxv6Vbt8sEKA87T0720tXV2": {
"name": "Karla Stanlee",
"userType": "Doctor",
"writePermission": true
}
}
我想对此进行过滤,以便获得以下内容:
"UsersCustom": {
"w14FKo72BieZwbxwUouTpN7UQm02": {
"name": "Naseebullah Ahmadi",
"userType": "Patient",
"writePermission": false
},
"SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
"name": "Levi Yeager",
"userType": "Patient",
"writePermission": false
}
}
这样做有什么意义?
请注意,这个对象 "User" 在现实中非常庞大(超过 1000 个条目)并且每个用户拥有的属性比单纯的 "name"、"userType" 和 "writePermission" 更多。
我需要过滤用户对象的原因是这样我就可以得到只有 (Patient) 的用户并得到那个 Patient 的 id 在另一个对象中查找最后将它们全部合并到一个对象中。
到目前为止我有什么
// user is the object as seen above
let Patients = users ? (
// I loop through them
Object.keys(users).map((uid, i) => {
// get individual patient
const patient = users[uid];
// check their userType
if (patient.userType === "Patient") {
let customPatient = {
uid: uid,
name: patient.name,
profession: patient.profession,
history: null,
ecg: null,
heartSound: null
};
this._healthRef(uid).then(health => {
customPatient.history = health;
return this._heartSoundRef(uid).then(HS => HS);
}).then(HS => {
customPatient.heartSound = HS;
return this._ecgRef(uid).then(a => a);
}).then(ecg => {
customPatient.ecg = ecg;
}).then(() => {
cusomPatients.push(customPatient);
})
}
})
)
我上面的解决方案虽然部分完成,但仍然效率低下且错误。因为我需要每个患者的 Id 进行其他查找
更新
目前,大多数解决方案都提供循环遍历条目,这意味着在最坏的情况下它将 运行 O(n)。有没有可能比O(n)更快地解决?
您可以使用 for-in
或 Object.keys
或(在现代 JavaScript 引擎上)Object.entries
.
for-in
提供了一种遍历对象的可枚举属性的方法;然后您可以使用这些 属性 名称来查找值:
var result = {};
for (var key in users) {
var entry = users[key];
if (entry.userType === "Patient") {
result[key] = entry;
}
}
实例:
var users = {
"w14FKo72BieZwbxwUouTpN7UQm02": {
"name": "Naseebullah Ahmadi",
"userType": "Patient",
"writePermission": false
},
"SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
"name": "Levi Yeager",
"userType": "Patient",
"writePermission": false
},
"VoxHFgUEIwRFWg7JTKNXSSoFoMV2": {
"name": "Ernest Kamavuako",
"userType": "Doctor",
"writePermission": true
},
"hFoWuyxv6Vbt8sEKA87T0720tXV2": {
"name": "Karla Stanlee",
"userType": "Doctor",
"writePermission": true
}
};
var result = {};
for (var key in users) {
var entry = users[key];
if (entry.userType === "Patient") {
result[key] = entry;
}
}
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
Object.keys
为您提供对象的 own 可枚举属性的数组,因此:
var result = {};
Object.keys(users).forEach(function(key) {
var entry = users[key];
if (entry.userType === "Patient") {
result[key] = entry;
}
});
实例:
var users = {
"w14FKo72BieZwbxwUouTpN7UQm02": {
"name": "Naseebullah Ahmadi",
"userType": "Patient",
"writePermission": false
},
"SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
"name": "Levi Yeager",
"userType": "Patient",
"writePermission": false
},
"VoxHFgUEIwRFWg7JTKNXSSoFoMV2": {
"name": "Ernest Kamavuako",
"userType": "Doctor",
"writePermission": true
},
"hFoWuyxv6Vbt8sEKA87T0720tXV2": {
"name": "Karla Stanlee",
"userType": "Doctor",
"writePermission": true
}
};
var result = {};
Object.keys(users).forEach(function(key) {
var entry = users[key];
if (entry.userType === "Patient") {
result[key] = entry;
}
});
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
Object.entries
提供了一个可迭代对象,它由每个自己的名称和值组成,可枚举 属性。这是很新的。因此,例如(在 ES2015+ 语法中,ES2017 中添加了 Object.entries
但可以填充):
const result = {};
for (const [key, value] of Object.entries(users)) {
if (value.userType === "Patient") {
result[key] = value;
}
}
实例:
const users = {
"w14FKo72BieZwbxwUouTpN7UQm02": {
"name": "Naseebullah Ahmadi",
"userType": "Patient",
"writePermission": false
},
"SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
"name": "Levi Yeager",
"userType": "Patient",
"writePermission": false
},
"VoxHFgUEIwRFWg7JTKNXSSoFoMV2": {
"name": "Ernest Kamavuako",
"userType": "Doctor",
"writePermission": true
},
"hFoWuyxv6Vbt8sEKA87T0720tXV2": {
"name": "Karla Stanlee",
"userType": "Doctor",
"writePermission": true
}
};
const result = {};
for (const [key, value] of Object.entries(users)) {
if (value.userType === "Patient") {
result[key] = value;
}
}
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
您可以在对象键上使用 reduce()
方法并从中构建新对象。
const obj = {"Users":{"w14FKo72BieZwbxwUouTpN7UQm02":{"name":"Naseebullah Ahmadi","userType":"Patient","writePermission":false},"SXMrXfBvexQUXfnVg5WWVwsKjpD2":{"name":"Levi Yeager","userType":"Patient","writePermission":false},"VoxHFgUEIwRFWg7JTKNXSSoFoMV2":{"name":"Ernest Kamavuako","userType":"Doctor","writePermission":true},"hFoWuyxv6Vbt8sEKA87T0720tXV2":{"name":"Karla Stanlee","userType":"Doctor","writePermission":true}}}
const newObj = {
'UserCustom': Object.keys(obj.Users).reduce((r, k) => {
if(obj.Users[k].userType == 'Patient') r[k] = Object.assign({}, obj.Users[k])
return r;
}, {})
}
console.log(newObj)
使用 for...in
遍历对象并检查用户类型是否为 patient。
var users = {
"Users": {
"w14FKo72BieZwbxwUouTpN7UQm02": {
"name": "Naseebullah Ahmadi",
"userType": "Patient",
"writePermission": false
},
"SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
"name": "Levi Yeager",
"userType": "Patient",
"writePermission": false
},
"VoxHFgUEIwRFWg7JTKNXSSoFoMV2": {
"name": "Ernest Kamavuako",
"userType": "Doctor",
"writePermission": true
},
"hFoWuyxv6Vbt8sEKA87T0720tXV2": {
"name": "Karla Stanlee",
"userType": "Doctor",
"writePermission": true
}
}
};
for(let user in users.Users){
if(users.Users.hasOwnProperty(user) && users.Users[user].userType!=="Patient")
delete users.Users[user];
}
console.log(users);
这将修改对象,如果您想保留它,只需对原始对象执行 deep copy。
我的猜测是在解析过程中进行过滤可能是最有效的(还没有 measured/compaed):
j = '{"w14FKo72BieZwbxwUouTpN7UQm02":{"name":"Naseebullah Ahmadi","userType":"Patient","writePermission":false},"SXMrXfBvexQUXfnVg5WWVwsKjpD2":{"name":"Levi Yeager","userType":"Patient","writePermission":false},"VoxHFgUEIwRFWg7JTKNXSSoFoMV2":{"name":"Ernest Kamavuako","userType":"Doctor","writePermission":true},"hFoWuyxv6Vbt8sEKA87T0720tXV2":{"name":"Karla Stanlee","userType":"Doctor","writePermission":true}}'
o = JSON.parse(j, (k, v) => !v.userType || v.userType === 'Patient' ? v : void 0)
console.log(o)
缓存过滤后的对象会更有效地减少网络流量。
使用reduce
方法你可以得到你的对象
var data = {
"w14FKo72BieZwbxwUouTpN7UQm02": {
"name": "Naseebullah Ahmadi",
"userType": "Patient",
"writePermission": false
},
"SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
"name": "Levi Yeager",
"userType": "Patient",
"writePermission": false
},
"VoxHFgUEIwRFWg7JTKNXSSoFoMV2": {
"name": "Ernest Kamavuako",
"userType": "Doctor",
"writePermission": true
},
"hFoWuyxv6Vbt8sEKA87T0720tXV2": {
"name": "Karla Stanlee",
"userType": "Doctor",
"writePermission": true
}
};
var results = Object.keys(data).reduce(function(acc, val) {
if(data[val].userType === 'Patient') acc[val] = data[val];
return acc;
}, {});
console.log(results);