[英]What's the most concise way in javascript to find consecutive dups in an array, sum them up and reiterate?
我有一个数组:
const myArr = [1, 1, 1, 3, 2, 2, 4, 3];
如果将它传递给函数,它将产生如下输出:
//result: [2, 1, 3, 8, 3]
连续的前两个1
s和2
s是连续的重复项,因此将它们相加。
前两个连续的1
变为2
因此现在不匹配。
连续的2
变成4
因此它与下一个运行编号匹配,并再次求和,结果为8
尽管3
s是重复的,但由于它们不是连续的,所以我们不对其进行总结
如果有人可以使用javascript的数组函数map
或reduce
演示这一点,那就太好了。
没有任何递归就可能吗?
有人提到了它的可能,那么如果不使用递归的话我会很好
在此处添加此内容是因为有些人已经提供了答案。
如果是:
const myArr = [1, 1, 1, 1];
// result: [4]
const myArr = [1, 1, 1, 1, 3, 2, 2, 4, 3];
// result: [4, 3, 8, 3]
另一个我没想到的有趣案例:
const myArr = [1, 1, 2, 2];
//result [4, 2] instead of [2,4]
进行更改后,它应立即对照新阵列进行检查
假设仅将其用于数字数组,则此操作非常简单,可以进行reduce。
function duplicateAddition(input) {
var last;
var result = input;
do {
last = result;
result = last.reduce(function (carry, item) {
if (carry[carry.length - 1] == item) {
carry[carry.length - 1] *= 2;
} else {
carry.push(item);
}
return carry;
}, []);
} while (last.length != result.length);
return result;
}
假设数组总是包含数字,那么我能想到的最简洁的是
function merge(arr) {
var x = String(arr),
y = x.replace(/([^,]),\1/, (_,m)=>2*m);
return x.length == y.length ? y.split(",").map(Number) : merge(y);
}
如果要避免尾部递归,将其转换为循环很简单:
function merge(arr) {
var y = String(arr);
do {
var x = y;
y = x.replace(/([^,]),\1/, (_,m)=>2*m);
} while(x.length != y.length)
return y.split(",").map(Number);
}
要么
function merge(arr) {
for (var x=String(arr), y=""; x.length!=y.length; x=y.replace(/([^,]),\1/, (_,m)=>2*m))
y=x;
return x.split(",").map(Number);
}
顺便说一句,要更改算法的行为以从[2, 4]
1、1、2、2 [2, 4]
获得[2, 4]
而不是[4, 2]
[1, 1, 2, 2]
(即,找到所有重复项并在重复之前求和),您只需要将/g
lobal标志添加到正则表达式。
此解决方案使用递归生成器。 它具有的优点是,它几乎说出了什么意思,并且做了什么。
function* x([first, second, ...rest]) { if (first !== undefined) { if (first !== second) yield first; else second *= 2; yield* x([second, ...x(rest)]); } } function test(a) { console.log(Array.from(x(a))); } test([1, 1, 1, 3, 2, 2, 4, 3]); test([1, 1, 1, 1]); test([1, 1, 2, 2]);
在此解决方案中,输入[1, 1, 2, 2]
产生[2, 4]
。 这是因为逻辑将2, 2
贪婪地折叠为4
,然后与1, 1
产生的2
不匹配。 如果不需要此行为,则将上面的行更改为:
yield* x([second, ...rest]);
这是一个简单的游戏,从数组a
移到推送数组b
。 因此,如果a[0] === a[1]
,则从数组a
取出前两个项,求和并将其推入数组b
但是如果a[0] !== a[1]
则仅取第一个项项目并将其推入数组b
。 但是,在我们推中间值(代码段下面的t
)之前,我们检查了数组b
的最后一项,看它是否等于中间值。 如果它们相等,我们不只是将临时( t
)推到b
就将数组b
的最后一项加倍。
然后进行尾调用优化的递归调用。
function sumAndReduce(a, b = []){ var t = 0; if (!a.length) return b; t = a[0] === a[1] ? a.splice(0,2).reduce((p,c) => p+c) : a.splice(0,1)[0]; b[b.length-1] === t ? b[b.length-1] += t : b.push(t); return sumAndReduce(a,b); } var myArr = [1, 1, 1, 3, 2, 2, 4, 3], result = sumAndReduce(myArr); console.log(JSON.stringify(result)); console.log(JSON.stringify(sumAndReduce([1, 1, 1, 1]))); console.log(JSON.stringify(sumAndReduce([1, 1, 2, 2])));
好吧...如果您不希望递归,即使它是优化的尾调用,那么将上述代码转换为带有while循环的迭代代码也很简单。 我留给你..!
因此,我无法确定您根据输入[1,1,2,2]
发出的请求是否违反了初始条件,但这也是上述代码的修改版本,以符合要求。
function sumAndReduce(a, b = []){ var t = 0; if (!a.length) return b; t = a[0] !== a[1] || b[b.length-1] === a[0] ? a.splice(0,1)[0] : a.splice(0,2).reduce((p,c) => p+c); b[b.length-1] === t ? b[b.length-1] += t : b.push(t); return sumAndReduce(a,b); } var myArr = [1, 1, 1, 3, 2, 2, 4, 3], result = sumAndReduce(myArr); console.log(JSON.stringify(result)); console.log(JSON.stringify(sumAndReduce([1, 1, 1, 1]))); console.log(JSON.stringify(sumAndReduce([1, 1, 2, 2])));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.