【问题标题】:Assign ranks to objects by values in an array of objects按对象数组中的值为对象分配等级
【发布时间】:2016-01-12 13:36:54
【问题描述】:

我有一个这样的对象数组:

var data = {
    a: [
        { keyone:'c', keytwo: 'anna', keythree: 21, keyfour: 15 },
        { keyone:'a', keytwo: 'anna', keythree: 22, keyfour: 15 },
        { keyone:'s', keytwo: 'anna', keythree: 10, keyfour: 15 },
        { keyone:'v', keytwo: 'anna', keythree: 7, keyfour: 15 }
    ],

    b: [
        { keyone:'f', keytwo: 'any', keythree: 45, keyfour: 100 },
        { keyone:'b', keytwo: 'any', keythree: 146, keyfour: 100 },
        { keyone:'t', keytwo: 'any', keythree: 23, keyfour: 100 },
        { keyone:'h', keytwo: 'any', keythree: 11, keyfour: 100 }
    ]
  };

我想根据keythreekeyfour 的值在组内以及整个数据集中为每个对象分配等级。我该怎么做?

更新:我在上面的代码中描述了等级。

结果对象:

var data = {
    a: [
        { keyone:'c', keytwo: 'anna', keythree: 21, keyfour: 15, rankgroup: 3, rankall: 4 },

        { keyone:'a', keytwo: 'anna', keythree: 22, keyfour: 15, rankgroup: 4, rankall: 5 },

        { keyone:'s', keytwo: 'anna', keythree: 22, keyfour: 15, rankgroup: 2, rankall: 2 },

        { keyone:'v', keytwo: 'anna', keythree: 7, keyfour: 15, rankgroup: 1, rankall: 1 }
    ],

    b: [
        { keyone:'f', keytwo: 'any', keythree: 45, keyfour: 100 },

        { keyone:'b', keytwo: 'any', keythree: 146, keyfour: 100 },

        { keyone:'t', keytwo: 'any', keythree: 23, keyfour: 100 },

        { keyone:'h', keytwo: 'any', keythree: 11, keyfour: 100 }
    ]
};

我正在使用lodash。我的想法是首先根据这些键对数组进行排序,然后遍历原始对象,通过比较另一个键来插入排序索引。这是我尝试过的:

var keys = Object.keys(data);
var result = {};
var numkeys;
for(var i=0; i < keys.length; i++) {
    if(!numkeys) {
        var numkeys = _.keys(_.pick(data[keys[i]][0], _.isNumber));
  }

        for(var j=0;j<numkeys.length;j++) {
    var sorted = _.sortBy(data['a'], numkeys[j]);
        _.forEach(sorted, function(n, k) {

        //THIS FAILS
        var t = _.set(_.where(data[keys[i]], {keyone: n.keyone}), keys[i]+'rank', k);
        console.log(t);
        });

    }
  }

我该怎么做?我的逻辑似乎太复杂了,set 方法并没有按键更新原始对象,而是在主对象之后添加了一个新条目。

更新:注意22 与对象a 重复出现。这会导致在分配排名时出现问题,因为indexOf 将始终返回第一次出现的索引,因此第二次出现的索引永远不会分配给它,因此该值将是未定义的。

【问题讨论】:

  • 在整个数据集中是什么意思?你是指ab 还是在ab 内?
  • 应该对每个子数组进行排序,意思是a和be,并且应该w.r.t.到对象数组的整个列表。我将更新我的描述以添加这一事实。
  • 请添加排序数组的示例。
  • 我不想排序,排序会让我失去原来的索引。我想计算排名。我将发布一个带有排名的结果数组。

标签: javascript arrays sorting lodash ranking


【解决方案1】:

这就是我实现它的方式。

  1. 将所有keythree 收集到一个数组中并对它们进行排序(根据index 分配rankall)。

    var all = [];
    _.forEach(data, function (a, key) {
        _.forEach(a, function(n, k){
        all.push(n.keythree);
      });
    });
    all.sort(function(a,b){
        return a-b;
    });
    
  2. 分配等级

    _.forEach(data, function (a, key) {
        var sorted = _.sortBy(a, 'keythree');
        _.forEach(sorted, function(n, k) {
          var index = _.findIndex(data[key], {keyone: n.keyone});
          data[key][index]['rankgroup'] = k+1;
          data[key][index]['rankall'] = all.indexOf(n.keythree)+1;
        });
    });
    

检查这个fiddle


编辑

我正在为骗子创建另一个数组

_.forEach(a, function(n, k) {
    if (all.indexOf(n.keythree) !== -1) {
        dupes.push(n.keythree);
    }
    all.push(n.keythree);
});

以及获得这些欺骗项目的全球排名

    function getGlobalRank(n) {
    var val = n.keythree;
    if (sorted_dupes[val] === undefined) {
        sorted_dupes[val] = [];
        _.forEach(data, function(a, key) {
            _.forEach(_.where(a, {
                keythree: val
            }), function(b) {
                sorted_dupes[val].push(b);
            });
        });
        sorted_dupes[val] = _.sortByAll(sorted_dupes[val], ['keyfour', 'keytwo', 'keyone']);
    }
    return _.findIndex(sorted_dupes[val], {
        keyone: n.keyone,
        keytwo: n.keytwo,
        keythree: n.keythree,
        keyfour: n.keyfour
    }) + 1 + all.indexOf(val);
}

查看项目是否根据所有属性按keythreekeyfourkeytwokeyone 的顺序排序(如果您愿意,可以在_.sortByAll 中更改顺序)

代码看起来比我想象的要丑。将很快更新重构的代码

查看fiddle

【讨论】:

  • 非常感谢!小提琴看起来很完美!让我在我的实际数据中试试这个!
  • 如何检查重复项?我的意思是排名将如何处理重复值?我接受您的回答,因为我可以理解并修改它,以便以类似的方式对我的数据集中的所有 numeric 值进行排名。
  • 仅将非重复值推送到 all 数组会导致 1) 项目在其组中正确排名,但 2) 多个项目可以在全球范围内排名相同
  • 是的!我在浏览代码时遇到了这个问题。再次感谢。
  • @RutwickGangurde 你检查了更新的答案吗?有帮助吗?
【解决方案2】:

只用简单的 Javascript:

为了排名,必须以某种方式对数据进行排序。

此解决方案具有一个包含对象的数组以及对data 中给定对象的引用。然后对所有项目进行排序,原始数据得到它们的rankgrouprankall 属性。

编辑:现在重复的排名相同。

var data = { a: [{ keyone: 'g', keytwo: 'tina', keythree: 21, keyfour: 15 }, { keyone: 'c', keytwo: 'anna', keythree: 21, keyfour: 15 }, { keyone: 'a', keytwo: 'anna', keythree: 22, keyfour: 15 }, { keyone: 's', keytwo: 'anna', keythree: 10, keyfour: 15 }, { keyone: 'v', keytwo: 'anna', keythree: 7, keyfour: 15 }], b: [{ keyone: 'f', keytwo: 'any', keythree: 45, keyfour: 100 }, { keyone: 'b', keytwo: 'any', keythree: 146, keyfour: 100 }, { keyone: 't', keytwo: 'any', keythree: 23, keyfour: 100 }, { keyone: 'h', keytwo: 'any', keythree: 11, keyfour: 100 }] },
    group = {};

Object.keys(data).reduce(function (r, k) {
    return r.concat(data[k].map(function (a) {
        return { obj: k, ref: a };
    }));
}, []).sort(function (a, b) {
    return a.ref.keythree - b.ref.keythree || a.ref.keyfour - b.ref.keyfour;
}).forEach(function (a, i, aa) {
    if (i && a.ref.keythree === aa[i - 1].ref.keythree && a.ref.keyfour === aa[i - 1].ref.keyfour) {
        a.ref.rankgroup = group[a.obj];
        a.ref.rankall = group.rankall;
    } else {
        group[a.obj] = (group[a.obj] || 0) + 1;
        group.rankall = (group.rankall || 0) + 1;
        a.ref.rankgroup = group[a.obj];
        a.ref.rankall = group.rankall;
    }
});

document.write('<pre>' + JSON.stringify(data, 0, 4) + '</pre>');

【讨论】:

  • 谢谢!我也在尝试这个。
  • 赞成。我最终使用了@Venugopal 的解决方案,因为我可以根据我的目的对其进行修改,其中包括对我的数据中的所有numeric values 进行排名。
  • 您可以将更多的排序组添加到return a.ref.keythree - b.ref.keythree || a.ref.keyfour - b.ref.keyfour|| a.ref.keyfive - b.ref.keyfive,等等。
  • 啊哈。让我试试看。
  • 你将如何处理在同一个对象中存在欺骗的情况?受骗者应该获得相同的排名。
猜你喜欢
  • 2017-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-19
  • 1970-01-01
  • 1970-01-01
  • 2019-06-16
  • 2018-12-06
相关资源
最近更新 更多