【问题标题】:Javascript trying to sort array of objects based on inner object array valuesJavascript 尝试根据内部对象数组值对对象数组进行排序
【发布时间】:2020-04-21 07:20:45
【问题描述】:

我不确定这个问题是否有简单的解决方案,但我想根据这个对象数组的 y 值和父 x 键对具有嵌套对象数组的对象数组进行排序。困难的部分是两个数组组合在一起来表示一些数据。

这是数据结构

series: [
  {
    name: 'testData',
    data: [
      {x: abc, y: 488},
      {x: def, y: 65},
      {x: ghi, y: 380},
      {x: jkl, y: 190}
    ]
  },
  {
    name: 'testData2',
    data: [
      {x: abc, y: 241},
      {x: def, y: 232},
      {x: ghi, y: 72},
      {x: jkl, y: 724}
    ]
  }
]

在这个阶段,只有两个父对象,所以我需要比较每个对象并重新排序,最终结果会是这样的

[
  {
    name: 'testData',
    data: [
      {x: jkl, y: 190}, // total for key jkl y combined values is 914
      {x: abc, y: 488}, // total for key abc y combined values is 729
      {x: ghi, y: 380}, // total for key ghi y combined values is 452
      {x: def, y: 65}, // total for key def y combined values is 297
    ]
  },
  {
    name: 'testData2',
    data: [
      {x: jkl, y: 724}, // total for key jkl y combined values is 914
      {x: abc, y: 241}, // total for key abc y combined values is 729
      {x: ghi, y: 72}, // total for key ghi y combined values is 452
      {x: def, y: 232} // total for key def y combined values is 297
    ]
  }
]

我尝试了一些想法,但如果您在其他地方看到了不错的解决方案,似乎无法找到解决我的问题的方法,请随时链接它。

这是我尝试过的东西

series.forEach(obj => {
  obj.data.sort((a, b) => {
    return b.y - a.y;
  });
});

但它最终只是将每个数组中的最高值移动到顶部,而不是应该与另一个数组匹配的值。很难给出上下文,但我使用的是 Apexcharts,它使用数据来制作这样的图表:

    | testData | testData2
---------------------------
abc  ------ GraphBar ------ 
def  ------ AnotherBar ----
ghi  ------ thirdBar ------
jkl  ------ fourthBar -----
---------------------------

所以我需要根据两个对象数据数组的 y 值,弄清楚如何根据条形的累积值进行排序。

这就是预排序的样子

之后,你可以看到它正在修改数据

【问题讨论】:

  • 问题不清楚你想做什么。请添加您尝试过的任何代码
  • 对父对象进行排序,但究竟基于什么?我知道这与 data 数组有关,但这还不够信息
  • 如果还不够,我会添加更多上下文,我会使用几个循环将一些东西组合在一起,我希望有一个使用 reduce / map 运算符的更优雅的解决方案
  • 我看到了,但它并没有真正帮助。我觉得你想按总和排序,但这没有意义:jkl 的总和总是 914,在每个对象中。总和到处都是一样的,你不能这样排序。所以我还是不明白你的排序逻辑。
  • 我添加的内容是否提供了更多上下文?

标签: javascript arrays typescript ecmascript-6 apexcharts


【解决方案1】:

假设我们将变量命名为series

const series = [
    {
        name: 'testData',
        data: [
            { x: 'abc', y: 488 },
            { x: 'def', y: 65 },
            { x: 'ghi', y: 380 },
            { x: 'jkl', y: 190 }
        ]
    },
    {
        name: 'testData2',
        data: [
            { x: 'abc', y: 241 },
            { x: 'def', y: 232 },
            { x: 'ghi', y: 72 },
            { x: 'jkl', y: 724 }
        ]
    }
]

(请注意,我已经使 x 属性具有 string 值而不是像 abc 这样的裸标识符;我认为这就是您想要的)

我们可以像这样处理您的分类任务。首先,让我们获取一个对象,其键是x 值,其值是y 值的总和:

const sums = series.reduce(
    (s, r) => (r.data.forEach(xy => s[xy.x] = (s[xy.x] || 0) + xy.y), s),
    {} as Record<string, number>
);

console.log(sums); // { abc: 729, def: 297, ghi: 452, jkl: 914 }

请注意,我在reduce 中使用comma operator,其中第一部分进行突变,最后一部分交还要突变的对象。除了简洁之外,它不一定比使用for 循环更好。

现在我们可以使用sumsseries 中的data 进行排序:

series.forEach(v => v.data.sort((a, b) => sums[b.x] - sums[a.x]));

console.log(JSON.stringify(series,null,2));
/*
[
  {
    "name": "testData",
    "data": [
      {
        "x": "jkl",
        "y": 190
      },
      {
        "x": "abc",
        "y": 488
      },
      {
        "x": "ghi",
        "y": 380
      },
      {
        "x": "def",
        "y": 65
      }
    ]
  },
  {
    "name": "testData2",
    "data": [
      {
        "x": "jkl",
        "y": 724
      },
      {
        "x": "abc",
        "y": 241
      },
      {
        "x": "ghi",
        "y": 72
      },
      {
        "x": "def",
        "y": 232
      }
    ]
  }
]
*/

在我看来是合理的。好的,希望有帮助;祝你好运!

Link to code

【讨论】:

  • 非常感谢您的帮助,我只是想完全理解代码,为什么我们有 || 0,此时 (s[xy.x] || 0) + xy.y)?是为了确保它被定义?
  • 是的。 s[xy.x] 将开始未定义,因此我们需要确保在这种情况下将总和初始化为 0。如果出于某种原因我们需要初始化为 0 以外的其他值,那么 nullish 合并运算符 ?? 会比 || 更好,因为 0 是假的。
猜你喜欢
  • 2013-11-25
  • 2018-11-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-27
  • 1970-01-01
  • 2021-11-20
  • 2017-09-29
  • 2021-04-26
相关资源
最近更新 更多