减少a';原始和#x27;javascript数组转换为更紧凑的数组(对象)

减少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

在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 },
//   ...
// ]
或者,如果
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
变量设置为列表列表,或者现有的赋值是否正确?@Hrishi
input
数组只是一个简单的一维数组,其格式可以使三个组更清晰。(它是正确的。)本机数组函数还是速度?for
循环的
通常要快得多。@眯着眼于速度,但不以可读性和功能可用性为代价。(有时两者甚至可以相交!)本机函数无需:根据您的判断。您想在主数组上使用map()(以相互转换),和子数组上的reduce(对每个子数组进行总结)。很好!很高兴看到用于解决此问题的本机reduce函数。很遗憾您不能跳过“return acc”调用。如果我给这个数组的元素数不是
n
的精确倍数,那么它会在最后一个分区的末尾返回未定义的元素。它也不适用于其他分区大小。这可以通过更改
formatData
来解决,只需返回
参数即可。从设计角度来看,我是also不相信将分区的概念与以某种方式转换的概念相结合(通过
formatData
)每个分区中的元素都是理想的。最好有一个独立的分区器,然后让用户对分区做任何他想做的事情。初始数组是平面的。谢谢你的回答,但计算最小值、最大值、平均值并不是我想要达到的目标。请再次阅读该问题,并告诉我你认为我可以怎样做更清楚了。@aaaidan:我编辑了…逻辑是可热交换的,只需将不同的函数传递给map()而不是report();如果你使用可互换的通用部件,你不需要提前构建任何东西…@dandavis这听起来很合理,但请原谅,我对你在报告函数中使用
Math.min
/
max
reduce
感到有点困惑。他们让我相信你认为我想执行这些操作,所以我放弃了我回答了这个问题。令人惊讶的是,
flattogroup
看起来很有希望,我现在来看看。@aaaidan:是的,我刚刚填入了一些逻辑,但这是树中的杂草。噢,哇,递归分区函数!因为我知道的任何浏览器中都没有尾部递归,那么对于大型数据集,是否有可能出现堆栈溢出?@aaaidan不仅递归且易于堆栈溢出,而且具有破坏性——您的数组神奇地变为空!哇,好卖的家伙!