按对象数组中的值为对象分配排名

时间:2023-01-16 11:32:37

I have an array of objects like so:

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

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 }
    ]
  };

I want to assign ranks to each object, based on values of keythree and keyfour, within the groups as well as within the entire data set. How would I do it?

我想根据keythree和keyfour的值,在组内以及整个数据集中为每个对象分配排名。我该怎么办?

Update: I have depicted the ranks in my code above.

更新:我在上面的代码中描述了排名。

Resultant object:

结果对象:

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 }
    ]
};

I am using lodash. My idea is to first sort the array based on those keys, then loop over the original object, insert the sorted index by comparing another key. This is what I have tried:

我正在使用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);
        });

    }
  }

How would I do it? My logic seems too complex and the set method does not update the original object by key but adds a new entry after the main object.

我该怎么办?我的逻辑看起来太复杂了,set方法不会按键更新原始对象,而是在主对象之后添加一个新条目。

Update: Notice the duplicate occurrence of 22 for the object a. This leads to an issue when assigning ranks, since indexOf will always return the index of the first occurrence, hence the second occurrence will never have an index assigned to it and hence the value will be undefined.

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

2 个解决方案

#1


1  

this is how I achieved it.

这就是我实现它的方式。

  1. collect all keythree into an array and sort them (to assign rankall based on index).

    将所有keythree收集到一个数组中并对它们进行排序(根据索引分配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. assign ranks

    分配排名

    _.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;
        });
    });
    

check this fiddle

检查这个小提琴


EDIT

i'm creating another array for dupes

我正在为dupes创建另一个数组

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

and for getting the global rank for these dupe items

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

    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);
}

see that the items are sorted based on all the properties in the order keythree, keyfour, keytwo, keyone (you can change the order inside _.sortByAll if you want to)

看到项目是根据订单keythree,keyfour,keytwo,keyone中的所有属性进行排序的(如果你愿意,你可以改变_.sortByAll中的顺序)

the code looking uglier than i thought. will update the refactored code soon

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

check the fiddle

检查小提琴

#2


1  

Just in plain Javascript:

只是简单的Javascript:

For ranking, the data must be sorted, somehow.

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

This solution features an array with objects and the references to the given objects in data. Then all items are sorted and the original data gets their rankgroup and rankall property.

此解决方案具有一个包含对象的数组以及对数据中给定对象的引用。然后对所有项目进行排序,并且原始数据获得其rankgroup和rankall属性。

Edit: Now with same rank for duplicates.

编辑:现在具有相同的重复等级。

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>');

#1


1  

this is how I achieved it.

这就是我实现它的方式。

  1. collect all keythree into an array and sort them (to assign rankall based on index).

    将所有keythree收集到一个数组中并对它们进行排序(根据索引分配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. assign ranks

    分配排名

    _.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;
        });
    });
    

check this fiddle

检查这个小提琴


EDIT

i'm creating another array for dupes

我正在为dupes创建另一个数组

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

and for getting the global rank for these dupe items

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

    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);
}

see that the items are sorted based on all the properties in the order keythree, keyfour, keytwo, keyone (you can change the order inside _.sortByAll if you want to)

看到项目是根据订单keythree,keyfour,keytwo,keyone中的所有属性进行排序的(如果你愿意,你可以改变_.sortByAll中的顺序)

the code looking uglier than i thought. will update the refactored code soon

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

check the fiddle

检查小提琴

#2


1  

Just in plain Javascript:

只是简单的Javascript:

For ranking, the data must be sorted, somehow.

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

This solution features an array with objects and the references to the given objects in data. Then all items are sorted and the original data gets their rankgroup and rankall property.

此解决方案具有一个包含对象的数组以及对数据中给定对象的引用。然后对所有项目进行排序,并且原始数据获得其rankgroup和rankall属性。

Edit: Now with same rank for duplicates.

编辑:现在具有相同的重复等级。

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>');