在javascript中,我正在寻找一种处理数组的整洁方式,以便集合中的短,重复序列(元组)变为更紧凑的集合。我想将长度 3n 的数组转换为长度 n 的集合。
这是一个想象中的例子:
// A flat (1-dimensional) array of numbers for input
var input = [
1, 11, 5,
2, 12, 10,
3, 13, 6,
4, 14, 11,
... ];
// A custom "lambda". This is my main intent, the rest is just plumbing.
var formatData = function(a,b,c) {
return { foo: a, bar: b, woot: c };
};
var output = input.reduceMulti(3, formatData); // ficticious 'reduceMulti'!
// output:
// [
// { foo: 1, bar: 11, woot: 5 },
// { foo: 2, bar: 12, woot: 10 },
// { foo: 3, bar: 13, woot: 6 },
// { foo: 4, bar: 14, woot: 11 },
// ...
// ]
或者,output
中的那些对象很容易成为字符串或数组,如果formatData
返回不同的内容。
我正在寻找一种类似reduce
的解决方案,除了能够减少多个值。
获得高效的奖励积分,但最终解决方案应该是可读,可维护和可用的。
答案 0 :(得分:3)
您仍然可以使用reduce
,它还将索引和数组作为参数:
var formatData = function(x, y, z) {
return [x, y, z]
}
var reduceMulti = function(n, f, xs) {
return xs.reduce(function(acc, x, i, xs) {
if (i % n === 0) {
acc.push(f.apply(null, xs.slice(i, i+n)))
}
return acc
},[])
}
reduceMulti(3, formatData, input)
//^ [[1,11,5], [2,12,10], [3,13,6], [4,14,11]]
如果您为n
提供3
的值,那么您必须传递一个需要3个参数的函数。
答案 1 :(得分:2)
我将从一个简单的小例程开始,将数组划分为相同大小的段:
function partition(arr, n) {
return arr.length ? [arr.splice(0, n)].concat(partition(arr, n)) : [];
}
还有一点功能:
function sum(arr) { return arr.reduce(function(s, v) { return s + v; }); }
现在,我们将对原始数组进行分区并将其映射到统计度量对象:
partition(input, 3).map(function(seg) {
return {
max: Math.max.apply(0, seg),
min: Math.min.apply(0, seg),
mean: sum(seg)/seg.length};
};
})
如果您更喜欢非递归分段器:
function partition(arr, n) {
var result = [];
while (arr.length) { result.push(arr.splice(0, n)); }
return result;
}
这利用了Array#splice
的行为,它修改了数组以删除指定的元素并返回已删除元素的数组。
如果你真的想要完全实现你提出的语法,那么你需要将reduceMulti
放在Array原型上,而不是我建议的那样:
Array.prototype.reduceMulti = function(n, reducer) {
return partition(this, n).map(reducer);
}
var output = input.reduceMulti(3, formatData);
答案 2 :(得分:1)
将问题分解为多个步骤:对平面数组进行分组,使用map()
对每个数组进行转换,然后使用reduce
计算总和。
var r= [
1, 11, 5,
2, 12, 10,
3, 13, 6,
4, 14, 11,
];
function flatToGrouped(r, width){
var o=[];
for(var i=0, mx=r.length; i<mx; i+=width){
o.push(r.slice(i, i+width) );
}
return o.filter(Boolean);
}
function report(a,_,__){
return {
min: Math.min.apply(0,a),
max: Math.max.apply(0,a),
mean: a.reduce( function(a,b,_,__){ return a+b; } )
}
}
flatToGrouped(r, 3).map(report);
额外的形式参数看起来很奇怪,但它们使得函数运行速度比其他方式更快(我发现arity匹配改进了优化 - 我告诉所有人)。
编辑:我没有意识到最初的阵列是扁平的。您仍然可以在项目转换器上使用简单映射,并使用收集器来生成要分析的n级数组。通过将它们分成两部分,你不会被锁定为reduce,而是数组可以做的任何事情(map / reduce / filter / etc)。