简体   繁体   English

Javascript 在嵌套对象中按键排序对象

[英]Javascript sort object by key within nested objects

I have the following object:我有以下对象:

{
  4: {
    1: [
      { order: 1, name: 'Test 4' }
    ]
  },
  0: {
    15: [
      { order: 7, name: 'Test 1' },
      { order: 3, name: 'Test 3' },
    ],
    12: { 
      { order: 1, name: 'Test 2' }
    }
  }
}

Essentially what I am trying to achieve is to order this by the keys and then order further by the order property from within the nested value.基本上我想要实现的是通过键对其进行排序,然后通过嵌套值内的 order 属性进一步排序。 So in turn I get the following output:所以反过来我得到以下输出:

{
  0: {
    12: { 
      { order: 1, name: 'Test 2' }
    },
    15: [
      { order: 3, name: 'Test 3' },
      { order: 7, name: 'Test 1' },
    ]
  },
  4: {
    1: [
      { order: 1, name: 'Test 4' }
    ]
  }
}

I then want to completely flatten this so it's without any of the outer object and just the data within the order, the outcome would then be:然后我想完全压平它,这样它就没有任何外部对象,只有订单中的数据,结果将是:

[
  { name: 'Test 2' },
  { name: 'Test 3' },
  { name: 'Test 1' },
  { name: 'Test 4' }
]

I imagine this would be some kind of recursive operation which I need to do and I originally did it with something like the following but it got a bit messy:我想这将是我需要做的某种递归操作,我最初是用类似下面的东西来做的,但它有点乱:

Object.keys(obj)
  .sort()
  .reduce((acc, key) => { acc[key] = obj[key]; return acc; }, {});

You can sort each obj by keys using Object.keys(obj).sort() and then access each element by its key.您可以使用Object.keys(obj).sort()按键对每个 obj 进行排序,然后按其键访问每个元素。

Do this 2 times to get the array of object这样做2次得到object的数组

 const obj = { 4: { 1: [ { order: 1, name: 'Test 4' } ] }, 0: { 15: [ { order: 7, name: 'Test 1' }, { order: 3, name: 'Test 3' }, ], 12: [ { order: 1, name: 'Test 2' } ] } } let flatItems = [] const keys = Object.keys(obj).sort() for (const key of keys){ const subObj = obj[key] const subKeys = Object.keys(subObj).sort() for(const subKey of subKeys){ flatItems = flatItems.concat(subObj[subKey].sort((a, b) => a.order - b.order)) } } console.log(flatItems)

Object keys can't easily be sorted, the iteration order depends on different rules and isn't straightforward to work with. Object 键不容易排序,迭代顺序取决于不同的规则,使用起来并不简单。 As a result you're better off converting your object into an array of key-value pair arrays (entries), and then sort that array rather than trying to sort your object.因此,您最好将 object 转换为键值对数组 arrays(条目),然后对该数组进行排序,而不是尝试对 object 进行排序。

To do this, you can create a recursive function ( sortEntries ) that takes your object and grabs the entries from it.为此,您可以创建一个递归 function ( sortEntries ),它获取您的 object 并从中获取条目 Using the key component of the entries, you can sort based on that.使用条目的关键组件,您可以根据它进行排序 Once you've sorted the entries, you can .flatMap() the result of recursively sorting your nested object value by calling the sortEntries function again.对条目进行排序后,您可以.flatMap()通过再次调用sortEntries function 对嵌套的 object 值进行递归排序的结果。 For the base case (termination case), you can stop the recursion once you've found a value that is an array, which for that you can sort by the order property for your objects and then .map() each object to extract only the name property.对于基本情况(终止情况),您可以在找到一个数组值后停止递归,为此您可以按对象的order属性排序,然后.map()每个 object 仅提取name属性。 Each array returned by .map() will be merged together into one resulting array due to the previous .flatMap() call:由于之前的.flatMap()调用,由.map()返回的每个数组都将合并到一个结果数组中:

 const obj = { 4: { 1: [ { order: 1, name: 'Test 4' } ] }, 0: { 15: [ { order: 7, name: 'Test 1' }, { order: 3, name: 'Test 3' }, ], 12: [ { order: 1, name: 'Test 2' } ] } }; const sortEntries = (obj) => { return Array.isArray(obj)? obj.slice().sort((a, b) => a.order - b.order).map(({name}) => ({name})): Object.entries(obj).sort(([a], [b]) => a - b).flatMap(([, val]) => sortEntries(val)); } const res = sortEntries(obj); console.log(res);

Anotner one sorting approach另一种排序方法

 const obj = {4:{1:[{order:1,name:'Test 4'}]},0:{15:[{order:7,name:'Test 1'},{order:3,name:'Test 3'},],12:[{order:1,name:'Test 2'}]}}; const result = Object.entries(obj).flatMap(([u1, v1]) => Object.entries(v1).flatMap(([u2, v2]) => v2.map((v3) => ({ key: u1*1_000 + u2 + v3.order/1_000, item: v3 })) ) ).sort(({ key: a }, { key: b }) => a - b).map(({ item }) => item); console.log(result);
 .as-console-wrapper { max-height: 100%;important: top: 0 }

The integer properties (in the range of 32 bit unsigned integers) don't need sorting, as iteration over them (eg via Object.values ) is by specification already sorted by those integer keys. integer 属性(在 32 位无符号整数范围内)不需要排序,因为对它们的迭代(例如通过Object.values )是按规范已经按这些 Z157DB7DF530023572EZ8515B 键排序的规范。 So the logic needs to focus only on sorting the inner objects, and it will be fine.所以逻辑只需要关注内部对象的排序,就可以了。

 const flatSort = obj => Array.isArray(obj)? [...obj].sort((a, b) => a.order - b.order).map(a => a.name): Object.values(obj).flatMap(flatSort); const obj = { 4: { 1: [ { order: 1, name: 'Test 4' } ] }, 0: { 15: [ { order: 7, name: 'Test 1' }, { order: 3, name: 'Test 3' }, ], 12: [ { order: 1, name: 'Test 2' } ] } }; const res = flatSort(obj); console.log(res);

Full Key/Value object sorting (array values included):全键/值对象排序(包括数组值):

function sortKeys(object) {
  if (Array.isArray(object))
    return object.sort().map((obj) => (typeof obj === "object" ? sortKeys(obj) : obj));

  const sortedObj = {};
  const keys = Object.keys(object).sort();

  for (var index in keys) {
    const key = keys[index];
    if (typeof object[key] === "object") {
      sortedObj[key] = sortKeys(object[key]);
    } else {
      sortedObj[key] = object[key];
    }
  }

  return sortedObj;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM