对不起,一个简单的问题:
我有一个2D元素数组,其中每个元素都封装了一个int值。像这样:
MyComponent = {... , value: 2, ...} // each instance has a value property
MyArray = [
[Component1, Component2],
[Component3],
[Component4, Component5, Component6, Component7],
... ]
我想根据每行中value
个元素的总和对我的2D数组行进行排序。
稍微详细一点:我有多组选择(组合)供用户选择,其中任何组中的每个选项都有一定的值。我想首先显示sum
或total
最高的组合(因此它是降序)。
在javascript中实现这一目标的快速有效方法是什么?
答案 0 :(得分:1)
以下排序函数预先计算行总和以避免冗余求和,并将总和存储在Map
中,以便在array.sort()
回调中快速检索:
// Sort a 2D array in-place by the sum of its rows:
function sortByRowSum(array) {
let sums = new Map(array.map(row =>
[row, row.reduce((sum, element) => sum + element, 0)]
));
return array.sort((a, b) => sums.get(a) - sums.get(b));
}
// Example:
console.log(sortByRowSum([[1, 3], [2], [0, 1, 8], [0]]));
由于您的行元素不是上面示例中的简单数字,因此您需要将reduce回调调整为行元素的结构,例如:
let sums = new Map(array.map(row =>
[row, row.reduce((sum, component)=> sum + component.value, 0)]
));
答案 1 :(得分:1)
var originalArray = [
[{value: 2}, {value: 3}],
[{value: 11}],
[{value: 1}, {value: 2}, {value: 3}, {value: 4}]
];
var sortedArray = originalArray.sort(function(row1, row2) {
add = function(a, b) {return a + b.value};
return row1.reduce(add, 0) - row2.reduce(add, 0);
});
console.log(sortedArray);

让我们打破这个,不管吗?
我们从原始数组开始:
var originalArray = [
[{value: 2}, {value: 3}],
[{value: 11}],
[{value: 1}, {value: 2}, {value: 3}, {value: 4}]
];
然后我们对它进行排序。让我们从内到外发挥作用。首先,我们如何计算一行的总和?我们可以使用reduce
函数:
exampleRow = [{value: 2}, {value: 3}];
add = function(a, b) {return a + b.value};
console.log(exampleRow.reduce(add, 0));

reduce
函数接受另一个函数(在这种情况下为add
)并使用它迭代一个数组并将 reduce 它转换为单个项目(通常是一个数字) )。 reduce
需要一个函数,它接受两个参数 - 运行总计和下一个项目。大致减少以下内容:
array.prototype.reduce = function(fn, initial) {
runningTotal = initial;
for (var i = 0; i <= array.length; i++) {
runningTotal = fn(runningTotal, array[i]);
}
return runningTotal;
}
总之,它以初始值开头,然后反复运行你的函数,每次运行都使用最后一次运行的输出和数组中的下一项。
在我们的案例中,fn
函数为add
:
add = function(a, b) {return a + b.value};
add
非常简单;它需要运行总计(a
)并添加下一个项目value
(b
)。在整个数组中,这简化为0 + array[0].value + array[1].value + ... + array[array.length-1].value
- 数组的总和。
我们快到了!最后一部分是实际排序。我们使用sort
函数执行此操作(惊喜!)。 sort
函数还接受一个函数,该函数具有两个用于迭代数组的参数。但是,您为sort
提供的功能必须返回一个数字。 sort
使用此函数来比较两个参数;如果输出为正,则第一项为“更大”,而如果输出为负,则第二项“更大”。 (如果输出为零,则它们相等。)sort
使用它来按升序对数组进行排序。
在我们的例子中,我们的函数接受两行并返回第一行的总和减去另一行的总和。这意味着如果第一行的总和更大,则ist将在数组中稍后出现,反之亦然。
答案 2 :(得分:1)
为自己比较2种解决方案的效果,可能对其他人有用,可以随意优化:https://jsperf.com/sort-array-by-sum-of-rows/1
我的Firefox,Chrome和Edge只有30-70%的改进(我的ES6代码无法在IE11中编译),因此可读性降低不值得恕我直言:
const simpleSorter = (arr) => [...arr].sort(
(a, b) => b.reduce((sum, i) => sum + i.value, 0) -
a.reduce((sum, i) => sum + i.value, 0)
)
const fasterSorter = (arr) => {
// note: should use stable sort for equal row scores
const rowScores = arr.map((row, index) => ({
score: row.reduce((sum, i, index) => sum + i.value, 0),
index
})).sort((a, b) => b.score - a.score)
return rowScores.map(s => arr[s.index])
}
const rand = () => Math.floor((Math.random() * 10)) + 1
const idGenerator = (() => {
let i = 0
return () => i++
})()
const componentGenerator = () => ({a: 'x', value: rand(), id: idGenerator()})
const rowGenerator = () => [...Array(rand())].map(componentGenerator)
const myArray = [...Array(10)].map(rowGenerator)
const prettyPrinter = (arr) => arr.map(i => {
const temp = i.map(j => j.value)
return temp.join(' + ') + ' = ' + temp.reduce((a, b) => a + b)
})
const myArraySimpleSorted = simpleSorter(myArray)
const myArrayFasterSorted = fasterSorter(myArray)
console.log('test',
prettyPrinter(myArraySimpleSorted).toString() ===
prettyPrinter(myArrayFasterSorted).toString())
console.log('myArray', prettyPrinter(myArray))
console.log('myArraySimpleSorted', prettyPrinter(myArraySimpleSorted))
console.log('myArrayFasterSorted', prettyPrinter(myArrayFasterSorted))
console.log('first in myArray', myArray[0][0])
console.log('first in myArraySimpleSorted', myArraySimpleSorted[0][0])
&#13;