如何有效地过滤对象的对象?

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-inObject.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);