假设我有一个包含多个元素的数组arr
。我想创建一个由arr
(数组数组)组成的数组的数组,其中每个组由匹配某个条件fn
的下一个元素和顺序中的每个下一个元素组成,直到下一个匹配。
所以我想通过匹配元素开始分组数组。 我做了以下代码来做到这一点,但这对我来说太迫切了:
var sliceGroupingBy = (arr, fn) => {
var newArray = [];
arr.forEach(el => {
if (fn(el)) {
newArray.push([el]);
} else {
newArray.slice(-1)[0].push(el);
}
});
return newArray;
};
示例:
var in = [1, 2, 4, 6, 3, 4, 6, 5, 7, 8, 8, 1];
var out = sortaGroupBy(in, x => x % 2 === 1);
// [ [ 1, 2, 4, 6 ], [ 3, 4, 6 ], [ 5 ], [ 7, 8, 8 ], [ 1 ] ]
我想知道更有效的方法是什么,只使用常规功能操作(没有if或aux。数组)。
答案 0 :(得分:2)
您可以使用reduce
而不是某些命令性循环来使其更具功能性:
function sliceGroupingBy(arr, fn) {
return arr.reduce((newArray, el) => {
if (fn(el))
newArray.push([el]);
else
newArray[newArray.length-1].push(el);
return newArray;
}, []);
}
如果您还想避免使用push
,无论出于何种原因,您都可以concat
:
const sliceGroupingBy = (arr, fn) =>
arr.reduce((newArray, el) =>
fn(el)
? newArray.concat([[el]]);
: newArray.slice(0, -1).concat(newArray.slice(-1).map(lastArray =>
lastArray.concat([el])
)
, []);
(“改变”数组的最后一个元素可以通过多种方式完成)
答案 1 :(得分:0)
总体效率低下但是:
let predicate = x => x % 2 === 1;
let partition = (pred, arr) => {
let res1 = arr.filter(pred);
let res2 = arr.filter(x => !pred(x));
return [res1, res2];
};
partition(predicate, [1,2,3,...]);
我永远不会在JavaScript中这样做(从代码中假设有问题的语言)。请参阅我对您问题的评论。
根据我对你正在做的事情的错误评论,
let xs = array.reduce((acc, x, i, arr) => {
let lastIndex = acc.reduce((y, z) => { y + z.length }, 0);
return predicate(x) || i === arr.length - 1 ?
acc.concat([arr.slice(lastIndex, i)]) :
acc;
}, []);
不使用语句,仅使用表达式,不使用变异,仅使用复制。如果不使用immutable.js或mori,我仍然不会这样做。它相当昂贵。
基于Bergi评论的最后一种方法的更高效版本:
let {result} = array.reduce((obj, x, i, arr) => {
let {lastIndex, result} = obj;
let passes = predicate(x) || i === arr.length - 1;
return {
lastIndex: passes ? i : lastIndex,
result: passes ? result.concat([arr.slice(lastIndex, i)]) : result
};
}, { lastIndex: 0, result: [] });