假设我有一个类似下面的输入数组
var inputArray = [
{a: 1, b: 1, c: 1, d: 1, value: 1, rank: 1},
{a: 1, b: 1, c: 1, d: 1, value: 2, rank: 2},
{a: 1, b: 1, c: 1, d: 1, value: 3, rank: 3},
{a: 1, b: 1, c: 1, d: 1, value: 4, rank: 4},
{a: 1, b: 1, c: 1, d: 1, value: 5, rank: 5},
{a: 1, b: 2, c: 1, d: 1, value: 1, rank: 1},
{a: 1, b: 2, c: 1, d: 1, value: 2, rank: 2},
{a: 1, b: 2, c: 1, d: 1, value: 3, rank: 3},
{a: 1, b: 2, c: 1, d: 1, value: 4, rank: 4},
{a: 1, b: 2, c: 1, d: 1, value: 5, rank: 5}
]
我想将我的inputArray
转换为以下outputArray
var outputArray = [
{
a: 1,
b: 1,
c: 1,
d: 1,
values:{
"1":{value: 1},
"2":{value: 2},
"3":{value: 3},
"4":{value: 4},
"5":{value: 5}
}
},
{
a: 1,
b: 2,
c: 1,
d: 1,
values:{
"1":{value: 1},
"2":{value: 2},
"3":{value: 3},
"4":{value: 4},
"5":{value: 5}
}
}
]
这意味着,我需要为a
,b
,c
和d
的相同属性创建一个字典,其中属性rank
的值是字典的键,字典的值是object
,其中唯一的属性是value
。
我们假设inputArray
不会针对a
,b
,c
和d
的组合进行排序。所以,我的方法就是这样,
(function(){
var inputArray = [
{a: 1, b: 1, c: 1, d: 1, value: 1, rank: 1},
{a: 1, b: 1, c: 1, d: 1, value: 2, rank: 2},
{a: 1, b: 1, c: 1, d: 1, value: 3, rank: 3},
{a: 1, b: 1, c: 1, d: 1, value: 4, rank: 4},
{a: 1, b: 1, c: 1, d: 1, value: 5, rank: 5},
{a: 1, b: 2, c: 1, d: 1, value: 1, rank: 1},
{a: 1, b: 2, c: 1, d: 1, value: 2, rank: 2},
{a: 1, b: 2, c: 1, d: 1, value: 3, rank: 3},
{a: 1, b: 2, c: 1, d: 1, value: 4, rank: 4},
{a: 1, b: 2, c: 1, d: 1, value: 5, rank: 5}
]
var temp = inputArray.sort(function(valA, valB){
if(valA.a === valB.a){
if(valA.b === valB.b){
if(valA.c === valB.c){
return valA.d < valB.d;
}
return valA.c < valB.c;
}
return valA.b < valB.b;
}
return valA.a < valB.a;
});
var outputArray = [],
currentIndex = 0;
for(var i = 0; i < inputArray.length; i++){
if(i > 0 && isConfigurationSame(inputArray[i], inputArray[i-1])){
outputArray[currentIndex-1].values[inputArray[i].rank] = {
value: inputArray[i].value
}
}
else{
outputArray.push(mapToOutputArrayObject(inputArray[i]));
currentIndex++;
}
}
console.log(outputArray);
function isConfigurationSame(A, B) {
return A.a === B.a
&& A.b === B.b
&& A.c === B.c
&& A.d === B.d;
}
function mapToOutputArrayObject(val){
var row = {};
row['a'] = val.a;
row['b'] = val.b;
row['c'] = val.c;
row['d'] = val.d;
row['values'] = {};
row.values[val.rank] = {
value: val.value
}
return row;
}
}());
但是问题是,如果输入数组的长度很大,这件事实际上会花费更多时间。这种多标准排序也需要很多时间。
是否有更好的方法以更少的时间更有效地完成结果?
感谢您的时间和耐心。
更新:a
,b
,c
和d
的值可以是整数或null
。>
答案 0 :(得分:5)
您可以创建一个哈希表并基于a,b,c和d生成唯一键:
const hash = {};
for(const { a, b, c, d, value, rank } of array) {
const key = JSON.stringify([a, b, c, d]); // generate a unique, but not random key
if(hash[key]) { // check if it already exists,
hash[key].values[rank] = value; // merge
} else {
hash[key] = { // create a new entry
a, b, c, d,
values: { [rank]: value },
};
}
}
const result = Object.values(hash); // turn the object into an array
即O(n),它比任何.sort
实现的时间复杂度都要好(但只有在a,b,c和d可序列化的情况下才有效(例如在这种情况下))。
答案 1 :(得分:3)
您可以使用Map
和一组分组键,并为每个组收集值。
var array = [{ a: 1, b: 1, c: 1, d: 1, value: 1, rank: 1 }, { a: 1, b: 1, c: 1, d: 1, value: 2, rank: 2 }, { a: 1, b: 1, c: 1, d: 1, value: 3, rank: 3 }, { a: 1, b: 1, c: 1, d: 1, value: 4, rank: 4 }, { a: 1, b: 1, c: 1, d: 1, value: 5, rank: 5 }, { a: 1, b: 2, c: 1, d: 1, value: 1, rank: 1 }, { a: 1, b: 2, c: 1, d: 1, value: 2, rank: 2 }, { a: 1, b: 2, c: 1, d: 1, value: 3, rank: 3 }, { a: 1, b: 2, c: 1, d: 1, value: 4, rank: 4 }, { a: 1, b: 2, c: 1, d: 1, value: 5, rank: 5 }],
keys = ['a', 'b', 'c', 'd'],
result = [],
map = new Map;
array.forEach(o => {
var key = keys.map(k => o[k]).join('|'),
temp = map.get(key);
if (!temp) {
map.set(key, temp = Object.assign(...keys.map(k => ({ [k]: o[k] })), { values: {} }));
result.push(temp);
}
temp.values[o.rank] = { value: o.value };
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 2 :(得分:1)
在这里使用Set,Map和const方法构建Values对象是一个刺。
var inputArray = [
{a: 1, b: 1, c: 1, d: 1, value: 1, rank: 1},
{a: 1, b: 1, c: 1, d: 1, value: 2, rank: 2},
{a: 1, b: 1, c: 1, d: 1, value: 3, rank: 3},
{a: 1, b: 1, c: 1, d: 1, value: 4, rank: 4},
{a: 1, b: 1, c: 1, d: 1, value: 5, rank: 5},
{a: 1, b: 2, c: 1, d: 1, value: 1, rank: 1},
{a: 1, b: 2, c: 1, d: 1, value: 2, rank: 2},
{a: 1, b: 2, c: 1, d: 1, value: 3, rank: 3},
{a: 1, b: 2, c: 1, d: 1, value: 4, rank: 4},
{a: 1, b: 2, c: 1, d: 1, value: 5, rank: 5}
];
const getValueObject = (a,b,c,d, arr) => {
let obj = {};
arr.filter(i => i.a === a &&
i.b === b &&
i.c ===c &&
i.d === d)
.forEach(item => obj[item.value] = item.rank);
return obj;
};
// Get a set based on the key a,b,c,d
let newArray = [...new Set(inputArray.map(({a,b,c,d}) => `${a},${b},${c},${d}`))]
.map(item => {
let [a,b,c,d] = item.split(',').map(i => parseInt(i));
// filter and add
return {
a: a,
b: b,
c: c,
d: d,
values: getValueObject(a,b,c,d, inputArray)
};
});
console.log(newArray);
答案 3 :(得分:1)
这是另一种选择,首先按a
,b
,c
和d
分组。然后在每个组上进行映射,以转换value
和rank
。
var inputArray = [{a: 1, b: 1, c: 1, d: 1, value: 1, rank: 1}, {a: 1, b: 1, c: 1, d: 1, value: 2, rank: 2}, {a: 1, b: 1, c: 1, d: 1, value: 3, rank: 3}, {a: 1, b: 1, c: 1, d: 1, value: 4, rank: 4}, {a: 1, b: 1, c: 1, d: 1, value: 5, rank: 5}, {a: 1, b: 2, c: 1, d: 1, value: 1, rank: 1}, {a: 1, b: 2, c: 1, d: 1, value: 2, rank: 2}, {a: 1, b: 2, c: 1, d: 1, value: 3, rank: 3}, {a: 1, b: 2, c: 1, d: 1, value: 4, rank: 4}, {a: 1, b: 2, c: 1, d: 1, value: 5, rank: 5}];
function groupBy(array, callback) {
return array.reduce((groups, item, ...args) => {
const key = callback(item, ...args),
group = groups[key] || (groups[key] = []);
group.push(item);
return groups;
}, {});
};
console.log(
Object
.values( groupBy(inputArray, ({a, b, c, d}) => [a, b, c, d]) )
.map(group => {
const {a, b, c, d} = group[0],
values = {};
group.forEach(({value, rank}) => values[rank] = {value});
return {a, b, c, d, values};
})
);