减少a';原始和#x27;javascript数组转换为更紧凑的数组(对象)
在javascript中,我正在寻找一种处理数组的整洁方法,这样集合中的短重复序列(元组)就可以简化为更紧凑的集合。我想将长度为3n的数组转换为长度为n的集合 下面是一个虚构的例子:减少a';原始和#x27;javascript数组转换为更紧凑的数组(对象),javascript,arrays,functional-programming,Javascript,Arrays,Functional Programming,在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
// 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 },
// ...
// ]
或者,如果formatData
返回不同的内容,则output
中的那些对象很容易成为字符串或数组
我正在寻找一种类似于reduce
的解决方案,除了能够将值减少到多个值之外
性能优异,但最终解决方案应该是可读的、可维护的和可用的。您仍然可以使用
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个参数的函数。将问题分解为几个步骤:将平面数组分组,使用map()
对每个数组进行变换,然后使用减少
计算总和
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);
var r=[
1, 11, 5,
2, 12, 10,
3, 13, 6,
4, 14, 11,
];
函数FlattoGroup(r,宽度){
var o=[];
对于(var i=0,mx=r.length;i我将从一个简单的小例程开始,将数组划分为大小相等的段:
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.prototype.reduceMulti = function(n, reducer) {
return partition(this, n).map(reducer);
}
var output = input.reduceMulti(3, formatData);
您是否打算将input
变量设置为列表列表,或者现有的赋值是否正确?@Hrishiinput
数组只是一个简单的一维数组,其格式可以使三个组更清晰。(它是正确的。)本机数组函数还是速度?for
循环的通常要快得多。@眯着眼于速度,但不以可读性和功能可用性为代价。(有时两者甚至可以相交!)本机函数无需:根据您的判断。您想在主数组上使用map()(以相互转换),和子数组上的reduce(对每个子数组进行总结)。很好!很高兴看到用于解决此问题的本机reduce函数。很遗憾您不能跳过“return acc”调用。如果我给这个数组的元素数不是n
的精确倍数,那么它会在最后一个分区的末尾返回未定义的元素。它也不适用于其他分区大小。这可以通过更改formatData
来解决,只需返回参数即可。从设计角度来看,我是also不相信将分区的概念与以某种方式转换的概念相结合(通过formatData
)每个分区中的元素都是理想的。最好有一个独立的分区器,然后让用户对分区做任何他想做的事情。初始数组是平面的。谢谢你的回答,但计算最小值、最大值、平均值并不是我想要达到的目标。请再次阅读该问题,并告诉我你认为我可以怎样做更清楚了。@aaaidan:我编辑了…逻辑是可热交换的,只需将不同的函数传递给map()而不是report();如果你使用可互换的通用部件,你不需要提前构建任何东西…@dandavis这听起来很合理,但请原谅,我对你在报告函数中使用Math.min
/max
和reduce
感到有点困惑。他们让我相信你认为我想执行这些操作,所以我放弃了我回答了这个问题。令人惊讶的是,flattogroup
看起来很有希望,我现在来看看。@aaaidan:是的,我刚刚填入了一些逻辑,但这是树中的杂草。噢,哇,递归分区函数!因为我知道的任何浏览器中都没有尾部递归,那么对于大型数据集,是否有可能出现堆栈溢出?@aaaidan不仅递归且易于堆栈溢出,而且具有破坏性——您的数组神奇地变为空!哇,好卖的家伙!