【问题标题】:object is sorted but its keys are not preserved using lodash sortBy对象已排序,但未使用 lodash sortBy 保留其键
【发布时间】:2020-07-14 09:40:08
【问题描述】:

上下文

需要使用 lodash 按readingDate 对以下对象进行排序,我可以对其进行排序,但其索引未保留。

原始 JSON 对象

{
    "Inventory Creation": [
      {
        "id": 150,
        "reading": "12345",
        "readingDate": "2020-07-14"
      }
    ],
    "Inventory & Check-in": [
      {
        "id": 151,
        "reading": "12345",
        "readingDate": "2020-11-14"
      }
    ],
    "Check-in": [
      {
        "id": 152,
        "reading": "12345",
        "readingDate": "2020-08-14"
      }
    ]
}

我尝试过的代码

_.sortBy(unsorted, o => o[0].readingDate).reverse();

这里unsorted 包含上面的原始 JSON 对象

实际结果(我得到的)

{
    0: [
      {
        "id": 151,
        "reading": "12345",
        "readingDate": "2020-11-14"
      }
    ],
    1: [
      {
        "id": 152,
        "reading": "12345",
        "readingDate": "2020-08-14"
      }
    ],
    2: [
      {
        "id": 150,
        "reading": "12345",
        "readingDate": "2020-07-14"
      }
    ]
}

预期结果(我想要的)

{
    "Inventory & Check-in": [
      {
        "id": 151,
        "reading": "12345",
        "readingDate": "2020-11-14"
      }
    ],
    "Check-in": [
      {
        "id": 152,
        "reading": "12345",
        "readingDate": "2020-08-14"
      }
    ],
    "Inventory Creation": [
      {
        "id": 150,
        "reading": "12345",
        "readingDate": "2020-07-14"
      }
    ]
}

【问题讨论】:

  • 您的原始 JSON 对象 实际上是一个对象,而不是数组,_.sortBy 排序后返回一个数组。为什么要对对象进行排序?
  • 感谢更正,让我更新问题,使其更易于理解。
  • 没问题,虽然我还是不明白你为什么要对一个对象进行排序。
  • 实际上是我正在处理的任务的要求,我需要在列表中显示JSON对象上方,并且该列表应按readingDate排序
  • 我明白了,那么请注意 JavaScript 总是保证对象键的顺序,尤其是当这些键在字符串之间混合时和数字,如提到的here

标签: javascript arrays lodash


【解决方案1】:

步骤如下:

  • 将对象转换为键值对列表(_.toPairs() 或内置的Object.entries()
  • 对列表进行排序
  • 将键值对列表转换回对象(_.fromPairs() 或内置的Object.fromEntries()

下面的 sn-p 可以帮助你。我使用_.chain() 以获得更好的可读性

const data = {
  "Inventory Creation": [
    {
      id: 150,
      reading: "12345",
      readingDate: "2020-07-14",
    },
  ],
  "Inventory & Check-in": [
    {
      id: 151,
      reading: "12345",
      readingDate: "2020-11-14",
    },
  ],
  "Check-in": [
    {
      id: 152,
      reading: "12345",
      readingDate: "2020-08-14",
    },
  ],
}

const res = _.chain(data)
  .toPairs()
  .sortBy((p) => p[1][0].readingDate)
  .reverse()
  .fromPairs()
  .value()

console.log(res)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.19/lodash.min.js"></script>

【讨论】:

  • 很好的建议,但值得注意的是,如果键具有混合类型,则此(或任何其他方法)将不起作用。例如,如果我们将键 "Check-in" 更改为 1,最后输出是错误的,因为对象在 JS 中是如何工作的。
【解决方案2】:

这是集合/数组的组合。查看您正在使用的 lodash 函数以及它的用途。这不起作用,您正在尝试使用对象的数组函数。该函数完全按照它应该做的,对数组进行排序。但是没有办法以这种方式创建已排序的对象,它(即 lodash 函数)甚至不知道该对象。

话虽如此,这里有一个可行的解决方案(一般看一下 map/reduce):

const entries = Object.entries(unsortedArr);
const sorted = entries.sort((a,b) => a[1][0].readingDate < b[1][0].readingDate ? 1 : -1);
const reduced = sorted.reduce(
  (acc, obj) => {
    acc[obj[0]] = obj[1]
return acc},{});

你可以链接这些调用,但我试图让它更容易理解。
我刚刚偶然发现groupBy 也可以使用。

【讨论】:

    【解决方案3】:

    这是一个蛮力解决方案。首先对数组进行排序并存储键。然后用 sortedArray 中的键组成数组。

    var sortedArray = _.sortBy(unsortedArray, function(val, key){
        val[0].key = key;
        return val[0].readingDate;
    }).reverse();
    
    var sortedArrayWithIndex = {};
    
    _.each(sortedArray, function(val){
        var key = val[0].key;
        delete val[0].key;
        sortedArrayWithIndex[key] = val;
    });
    console.log(sortedArrayWithIndex);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-22
      • 1970-01-01
      • 1970-01-01
      • 2021-08-21
      • 1970-01-01
      • 2018-12-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多