如何按place.city排序键为ID的嵌套非数组对象(保留顶层ID)
按place.city排序并保留顶层ID键的解决方案
我太懂这种被不友好API结构坑到的感觉了——明明逻辑很简单,却因为数据格式卡壳。别慌,咱们用JavaScript原生方法就能完美解决,而且全程保留顶层的ID键。
核心思路
处理这种以ID为键的非数组对象,关键是先把它转换成可排序的结构,排序后再转回目标格式:
- 第一步:将顶层对象拆解为
[ID, 对应数据]的键值对数组 - 第二步:按每个数据项里的
place.city字段对数组排序 - 第三步:把排序后的数组转回对象(或用Map严格保留顺序)
代码实现
先补全你给出的示例数据,方便演示:
const rawData = { "123": { place: { city: "New York", country: "USA" }, person: { name: "Bob", age: 45 } }, "456": { place: { city: "London", country: "UK" }, person: { name: "Alice", age: 30 } }, "789": { place: { city: "Paris", country: "France" }, person: { name: "Charlie", age: 35 } } };
场景1:顶层ID对应单个含place.city的对象
这是最常见的情况,直接用下面的代码:
// 1. 把对象转成可排序的键值对数组 const entries = Object.entries(rawData); // 2. 按place.city排序(大小写不敏感,兼容特殊字符) entries.sort(([idA, dataA], [idB, dataB]) => { const cityA = (dataA?.place?.city || "").toLowerCase(); const cityB = (dataB?.place?.city || "").toLowerCase(); return cityA.localeCompare(cityB); }); // 3. 转回对象(注意:如果ID是数字字符串,JS对象会自动按数字升序排列,需严格顺序用Map) const sortedObj = Object.fromEntries(entries); // 若要严格保留排序后的顺序,用Map替代对象: const sortedMap = new Map(entries);
场景2:顶层ID对应多个子项(如你示例里的0、1键结构)
如果每个ID下还有嵌套的子条目需要排序,调整代码如下:
const rawDataWithChildren = { "123": { 0: { place: { city: "New York" }, person: { name: "Bob" } }, 1: { place: { city: "Boston" }, person: { name: "James" } } }, "456": { 0: { place: { city: "London" }, person: { name: "Alice" } }, 1: { place: { city: "Edinburgh" }, person: { name: "David" } } } }; const sortedWithChildren = {}; for (const [id, children] of Object.entries(rawDataWithChildren)) { // 对子条目转数组、排序、再转回对象 const sortedChildren = Object.fromEntries( Object.entries(children).sort(([keyA, childA], [keyB, childB]) => { const cityA = (childA?.place?.city || "").toLowerCase(); const cityB = (childB?.place?.city || "").toLowerCase(); return cityA.localeCompare(cityB); }) ); sortedWithChildren[id] = sortedChildren; }
重要注意事项
- 对象键顺序的坑:如果顶层ID是数字字符串(如"123"),JavaScript对象会自动把这些键按数字升序排列,不管你排序后的数组顺序。必须严格保留city排序顺序的话,一定要用
Map存储结果,Map会完全遵循插入顺序。 - 容错处理:代码里加了
?.可选链操作符和空字符串兜底,避免数据缺失时抛出报错。 - 多语言兼容:用
localeCompare()而不是简单的字符串比较,能正确处理带重音的城市名(如"Paris"和"Páris")。
内容的提问来源于stack exchange,提问作者imanu
相关产品推荐
相关产品推荐

