【问题标题】:Javascript sort by initial position and object propertyJavascript按初始位置和对象属性排序
【发布时间】:2018-03-15 16:58:17
【问题描述】:

我有一个对象数组:

[{
    id : 1,
    tag: "video"
 },
 {
    id : 2,
    tag: "music"
 },
 {
    id : 3,
    tag: "video"
 },
 {
    id : 4,
    tag: "music"
 },
 {
    id : 5,
    tag: "video"
 }]

我想根据 2 个因素对这个数组进行排序:

  1. 元素的初始位置
  2. 标签

基本上我应该将标签组合在一起,但同时保持添加项目的顺序,输出应该如下所示:

[{
    id : 1,
    tag: "video"
 },
 {
    id : 3,
    tag: "video"
 },
 {
    id : 5,
    tag: "video"
 },
 {
    id : 2,
    tag: "music"
 },
 {
    id : 4,
    tag: "music"
 }]

如您所见,现在它们按标签名称分组,但保留了初始顺序。 id=1 的项目在 id=2 的项目之前,因为它是最先添加的,依此类推。

请注意,我不能使用 id 字段进行这种排序,因为真实的 id 不是整数,它是一个无法比较的唯一字符串。所以我应该使用原始位置索引而不是 id。

我唯一看起来不太好的解决方案是编写一大块代码在初始数组上创建一个 for 并通过检查具有相同标签的最后一项来创建一个新数组,其中项目放置在完美位置添加到原始数组中并获取它的位置并将其添加到该位置的新数组中。

对此有任何最佳解决方案吗?谢谢

【问题讨论】:

  • 我重新打开了它,因为它没有按字母顺序排序。这更像是一个分组问题,而不是一个排序问题。

标签: javascript arrays sorting object properties


【解决方案1】:

var arr = [{
    id : 1,
    tag: "video"
 },
 {
    id : 2,
    tag: "music"
 },
 {
    id : 3,
    tag: "video"
 },
 {
    id : 4,
    tag: "music"
 },
 {
    id : 5,
    tag: "video"
 }]


const result = arr
.map((item, i) => ({ index: i, id: item.id, tag:item.tag }))
.sort((a, b) =>  a.tag < b.tag )

console.log(result)

【讨论】:

    【解决方案2】:

    您可以使用sorting with map 和一个对象作为标签首次出现的位置。

    第一个map

    生成一个具有索引和位置属性的数组,它反映了第一个按位置排序,第二个按索引排序。

    [
        {
            index: 0,
            pos: 0
        },
        {
            index: 1,
            pos: 1
        },
        {
            index: 2,
            pos: 0
        },
        {
            index: 3,
            pos: 1
        },
        {
            index: 4,
            pos: 0
        }
    ]
    

    sort

    获取对象的位置和索引属性,并用它对临时数组进行排序。

    第二个map

    获取临时数组并通过从原始数组中获取对象来呈现结果并返回给定索引处的项目。

    var data = [{ id : 1, tag: "video" }, { id : 2, tag: "music" }, { id : 3, tag: "video" }, { id : 4, tag: "music" }, { id : 5, tag: "video" }],
        pos = Object.create(null),
        result = data
            .map(function (o, i) {
                (o.tag in pos) || (pos[o.tag] = i);
                return { index: i, pos: pos[o.tag] };
            })
            .sort(function (a, b) {
                return a.pos - b.pos || a.index - b.index;
            })
            .map(function (o) {
                return data[o.index];
            });
    
    console.log(result);

    【讨论】:

      【解决方案3】:

      您可以将reduce 数组按正确顺序分成子数组,然后通过应用Array#concat 将它们展平:

      var data = [{"id":1,"tag":"video"},{"id":2,"tag":"music"},{"id":3,"tag":"video"},{"id":4,"tag":"music"},{"id":5,"tag":"video"}];
      
      var helper = Object.create(null);
      var result = [].concat.apply([], data.reduce(function(r, o) {
        var arr;
        
        if(helper[o.tag] === undefined) {
           helper[o.tag] = r.push([]) - 1;
        }
        
        arr = r[helper[o.tag]];
        
        arr.push(o);
        
        return r;
      }, []));
      
      console.log(result);

      还有一个使用 Map 的 ES6 解决方案:

      const data = [{"id":1,"tag":"video"},{"id":2,"tag":"music"},{"id":3,"tag":"video"},{"id":4,"tag":"music"},{"id":5,"tag":"video"}];
      
      const result = [].concat(...data.reduce((r, o) => {
        const arr = r.get(o.tag) || [];
        arr.push(o);
        return r.set(o.tag, arr);
      }, new Map()).values());
      
      console.log(result);

      【讨论】:

      • 由于某种奇怪的原因,stackoverflow sn-p 不运行代码/显示结果。代码本身有效。
      • prop 的名称无关紧要(只要您更新代码),内容也无关紧要,如果它是原语(字符串、数字等...) .
      • 代码中没有问题。这是 stackoverflow sn-p 沙箱中的问题。如果它在 chrome 控制台中,它可以在 chrome 中运行 :)
      • 他们在做同样的事情。如果浏览器支持不是问题,我会选择 ES6,因为它更紧凑,并且不需要外部帮助对象。
      • 您是否已将所有o.tag 语句更新为o.event 语句? - const result = [].concat(...data.reduce((r, o) =&gt; { const arr = r.get(o.event) || []; arr.push(o); return r.set(o.event, arr); }, new Map()).values());
      猜你喜欢
      • 2013-10-28
      • 1970-01-01
      • 2011-09-06
      • 2010-11-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多