JavaScript:使用高阶函数编写此解决方案

时间:2018-03-22 21:19:26

标签: javascript for-loop foreach

我处理了一个问题,你会得到一系列数字和一个目标总和,找到一对总和达到目标数的数字是你的工作。这是我使用简单嵌套for循环的解决方案:

function findPairForSum(integers, target) {
  var output = [];

  for (var i = 0; i < integers.length; i++) {

    for (var j = 0; j < integers.length; j++) {

      if (i !== j && integers[i] + integers[j] === target) {
        output.push(integers[i], integers[j]);
        return output;
      }
    }
  }
  return 'not possible';
}

findPairForSum([3, 34, 4, 12, 5, 2], 9);  // --> [4, 5]

我的问题是,是否有更简洁的方法来使用更高阶函数编写此解决方案(也许是forEach?)

这是我尝试使用forEach:

function findPairForSum(integers, target) {
  var output = [];

  integers.forEach(function(firstNum) {
    integers.forEach(function(secondNum) {

      if (firstNum + secondNum === target) {
        output.push(firstNum, secondNum);
      }
    })
  })

  if (output === []) {
    return 'not possible'; 
  }  
  return output;
}

findPairForSum([3, 34, 4, 12, 5, 2], 9); // --> [ 4, 5, 5, 4 ]

我尝试在两次推送后返回,但它没有返回任何东西。所以相反,我把回报放在最后。

为什么在最初的两次推送后它会回来?我希望它停在那里,只推两个数字。相反,通过将回报放在最后,它推了4个数字。它应该是[4,5],但我得到了类似[4,5,5,4]的内容。

非常感谢任何建议和帮助!

6 个答案:

答案 0 :(得分:2)

假设我们有一组数字,我们必须找到2个数字的子集,其总和为9

Numbers: 4, 5, 6

您当前的代码会使用ij0length进行迭代。这意味着以下迭代符合条件:

Indices: 0, 1, 2
Numbers: 4, 5, 6   //        (i)          (j)
----------------   //         ↓            ↓
         i  j      // Numbers[0] + Numbers[1] === 9
         j  i      // Numbers[1] + Numbers[0] === 9

如您所见,数字4和5在两次迭代中匹配两次:

  • i === 0 && j === 1
  • i === 1 && j === 0

您可以通过确保满足一个简单条件来避免这种情况:

j必须始终大于i

通过在内部j循环中使用i + 1初始化for,可以满足此条件:

for (var i = 0; i < integers.length; i++) {
    for (var j = i + 1; j < integers.length; j++) {
        // ...
    }
}

这样,当j0时,i永远不会是1,因为内部for循环将在i之前运行完成再次增加。一旦发生这种情况,就会创建一个全新的内部for循环,其中j再次设置为i + 1。结果如下图所示:

Indices: 0, 1, 2
Numbers: 4, 5, 6
----------------
         i  j
         X  i     // ← j can never be 0 if (i === 1),
                  //   so the same set is never evaluated twice.

换句话说,最多只检查ij的以下组合:

Indices: 0, 1, 2
----------------
         i  j
         i     j
            i  j
  

是否有更简洁的方法来使用更高阶函数编写此解决方案(也许是forEach?)

for循环实际上是一个很好的解决方案。在您第一次找到有效数字对后,它们允许您提前中断。另一方面,forEach或其他数组迭代器函数将一直持续到访问所有设置索引为止。

您实际上是在第一个示例中使用语句return output;

提前破解

当您对一组包含多个有效集的数字使用forEach时,您将始终收回所有涉及的数字:

Indices: 0, 1, 2, 3
Numbers: 4, 5, 6, 3    //        (i)          (j)
-------------------    //         ↓            ↓
         i  j          // Numbers[0] + Numbers[1] === 4 + 5 === 9
               i  j    // Numbers[2] + Numbers[3] === 6 + 3 === 9

forEachmapreduce等不允许您提前休息。以下代码段演示了上图中的此问题:< / p>

function findPairForSum(integers, target) {
    var output = [];

    integers.forEach(function(firstNum, i) {
    
        // slice(i + 1) has the same effect as for (var j = i + 1; ...)
        integers.slice(i + 1).forEach(function(secondNum, j) {
        
            if (firstNum + secondNum === target) {
            
                // There is no way here to stop the iteration of either
                // forEach call... T_T
                output.push(firstNum, secondNum);
            }
        });
    })

    if (output.length) {
        return output;
    }

    return 'not possible';
}

console.log(findPairForSum([4, 5, 6, 3], 9)); // --> [4, 5, 6, 3]

这就是为什么我强烈建议坚持使用这个特定用例的for循环。使用for循环,只要遇到一组有效的数字,就可以像return一样:

function findPairForSum(integers, target) {
    for (var i = 0; i < integers.length; i++) {
        for (var j = i + 1; j < integers.length; j++) {
            if (integers[i] + integers[j] === target) {
                return [integers[i], integers[j]];
            }
        }
    }

    return 'not possible';
}

console.log(findPairForSum([4, 5, 6, 3], 9)); // --> [4, 5]

答案 1 :(得分:1)

问题是,你从内部循环的数组开始迭代。您可以使用从外部循环的索引处开始加一个的副本,并在找到的值的早期退出。

但这并不能解决多对问题。结果完全错了。

&#13;
&#13;
function findPairForSum(integers, target) {
    var output = [];

    integers.forEach(function(firstNum, i) {
        integers.slice(i + 1).some(function(secondNum) {
            if (firstNum + secondNum === target) {
                output.push(firstNum, secondNum);
                return true;
            }
        });
    });
    return output.length && output || 'not possible';
}

//    console.log(findPairForSum([3, 34, 4, 12, 5, 2], 9));
console.log(findPairForSum([3, 34, 4, 4, 12, 5, 2, 4, 5], 9));
&#13;
&#13;
&#13;

对于解决方案,您需要记住使用哪些对。此方法仅使用一个循环和哈希表来计算缺失值。

如果找到一对,则计数器递减,并将两个值推送到结果集。

&#13;
&#13;
function findPairForSum(integers, target) {
    var hash = Object.create(null),
        output = [];

    integers.forEach(function(value) {
        if (hash[value]) {
            output.push(target - value, value);
            hash[value]--;
            return;
        }
        hash[target - value] = (hash[target - value] || 0) + 1;
    });
    return output.length && output || 'not possible';
}

console.log(findPairForSum([3, 34, 4, 4, 12, 5, 2, 4, 5], 9));
&#13;
&#13;
&#13;

答案 2 :(得分:1)

这可能是您的解决方案:

&#13;
&#13;
function findPairForSum(arr, sum) {
  var pairs = [];
  arr.forEach(n1 => {
    var n2 = arr.find(n2 => n1 + n2 == sum)
    if (n2) pairs.push([n1, n2]);
  });
  return pairs;
}


var sums = findPairForSum([3, 34, 4, 12, 6, 2], 9);
console.log(sums)
&#13;
&#13;
&#13;

答案 3 :(得分:0)

这是预料之中的,因为您没有比较索引 此内部数组应仅循环遍历大于外部索引的索引 您可以通过在forEach的回调函数中使用第二个参数index来实现此目的:

&#13;
&#13;
const ints = [3, 34, 4, 12, 5, 6, 2];

function findPairForSum(integers, target) {
  let result;
  integers.forEach((val1, idx1) => {
    integers.forEach((val2, idx2) => {
      if (idx1 < idx2 && val1 + val2 === target) {
        result = [val1, val2];
      }
    })
  })
  return result;
}

console.log(findPairForSum(ints, 9));
&#13;
&#13;
&#13;

答案 4 :(得分:0)

您可以使用 Array.prototype.some ,只要条件成立,它就会停止执行。见下面的代码。

function findPairForSum(arr, sum) {
  var pairs = [];
  arr.some(n1 => {
    var n2 = arr.find(n2 => n1 + n2 == sum)
    if (n2) {
      pairs.push(n1, n2); return true;
    };
    return false;
  });
  return pairs.length > 0 ? pairs : "not possible"; 
}
console.log(findPairForSum([3, 34, 4, 12, 7, 2], 9));

答案 5 :(得分:0)

使用reduce数组进入另一个数字等于目标value的数据:

&#13;
&#13;
const ints = [3, 34, 4, 12, 6, 2];
const value = 9;

const resp = ints.reduce((acc, ele, idx, self) => {
  let found = self.find(x => x + ele == value)
  return found ? [found, ele] : acc;
}, []);

console.log(resp); // [3, 6]
&#13;
&#13;
&#13;