繁体   English   中英

用javascript查找数组中连续的dups,对其求和并重申的最简洁方法是什么?

[英]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的数组函数mapreduce演示这一点,那就太好了。

  • 没有任何递归就可能吗? 有人提到了它的可能,那么如果不使用递归的话我会很好


编辑

在此处添加此内容是因为有些人已经提供了答案。

如果是:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM