如何优化JavaScript卡牌计数逻辑的链式调用实现?
问题:如何用链式调用实现Part2的功能?
我非常喜欢Part1的链式调用结构,但不得不将Part2拆分为part2Array和最终的part2变量,因为无法直接用链式调用完成逻辑。
原代码实现
const rawData = `Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36 Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11`; const cardObjects = (card) => { const cardNumber = card.match(/\d+(?=:)/)[0]; const winningNumbers = card .match(/(?<=:)(.*?)(?=\|)/)[0] .trim() .split(/\s+/); const punterNumbers = card .match(/(?<=\|)(.*)/)[0] .trim() .split(/\s+/); return { cardNumber, winningNumbers, punterNumbers }; }; const punterWin = (card) => { const matchingNumber = card.winningNumbers.filter((w) => card.punterNumbers.includes(w) ); return matchingNumber; }; const calculatePoints = (matchingNumber) => { const points = Math.pow(2, matchingNumber.length - 1); return points; }; const cardWin = (wins, i) => { const winCount = wins.length; const card = i + 1; const cardCount = 1; return { card, cardCount, winCount }; }; const cardAdd = (cardWinCount, i) => { const winCount = cardWinCount.winCount; for (let x = 0; x < winCount; x++) { part2Array[i + x + 1].cardCount += cardWinCount.cardCount; } }; // Part1 链式调用实现 const part1 = rawData .split(/\n/) .map(cardObjects) .map(punterWin) .map(calculatePoints) .filter((a) => a >= 1) .reduce((acc, cur) => acc + cur); console.log(part1); // Part2 拆分实现 const part2Array = rawData .split(/\n/) .map(cardObjects) .map(punterWin) .map(cardWin); part2Array.forEach(cardAdd); const part2 = part2Array .map((card) => card.cardCount) .reduce((acc, cur) => acc + cur); console.log(part2);
尝试链式调用失败的代码
const part2 = rawData .split(/\n/) .map(cardObjects) .map(punterWin) .map(cardWin) .forEach(cardAdd) .map((card) => card.cardCount) .reduce((acc, cur) => acc + cur);
失败原因:forEach返回undefined,无法继续链式调用后续方法;同时cardAdd依赖外部的part2Array变量修改后续元素计数,没法直接嵌入链式流程。
请问有没有更简洁的Part2实现方式?
解决方案:用
reduce实现链式调用 可以通过reduce维护卡片计数数组,把修改逻辑整合到链式调用中,无需外部数组变量,同时还能合并冗余步骤。
优化后的链式实现
const part2 = rawData .split(/\n/) // 合并cardObjects、punterWin、cardWin的逻辑,减少链式层级 .map((cardStr, index) => { const winningNumbers = cardStr.match(/(?<=:)(.*?)(?=\|)/)[0].trim().split(/\s+/); const punterNumbers = cardStr.match(/(?<=\|)(.*)/)[0].trim().split(/\s+/); const winCount = winningNumbers.filter(num => punterNumbers.includes(num)).length; return { card: index + 1, cardCount: 1, winCount }; }) // 用reduce替代forEach,处理卡片计数的累加逻辑 .reduce((cardList, currentCard, idx) => { // 根据当前卡片的赢数,给后续卡片增加计数 for (let x = 0; x < currentCard.winCount; x++) { const targetIdx = idx + x + 1; if (targetIdx < cardList.length) { cardList[targetIdx].cardCount += currentCard.cardCount; } } return cardList; }) // 汇总所有卡片的数量 .reduce((total, { cardCount }) => total + cardCount, 0); console.log(part2);
优化点说明
- 替换
forEach为reduce:reduce会返回处理后的数组,能继续链式调用后续方法,解决了原链式调用中断的问题。 - 合并冗余步骤:把
cardObjects、punterWin、cardWin的逻辑合并到一个map中,减少链式层级,提升代码效率。 - 移除外部依赖:无需单独定义
part2Array变量,所有逻辑都在链式调用中完成,保持代码简洁。
内容的提问来源于stack exchange,提问作者Phil
相关产品推荐
相关产品推荐

