简体   繁体   中英

Use reduce() method to find a skipped number in an array of consecutive numbers

I'm trying to use the reduce() method to find one skipped (missing) number in an array of (sometimes almost) consecutive numbers. Only one number will be missing at most. This is my codepen: http://codepen.io/PiotrBerebecki/pen/zBrRVd

For example,
findMissing([1,2,3,5]) should return 4

findMissing([1,2,3,4]) should return undefined

findMissing([2,3,4,6]) should return 5

findMissing([2,4,5,6]) should return 3

The code that I developed seems to work fine if there is indeed a number that was skipped. But it returns an undesired value if all numbers are present. Would you know how to fix it?

My JS code:

function findMissing(arr) {
  return arr.reduce(function(prev, curr) { 
    if (curr - prev !== 1) {
      return curr - 1;
    }
  });
}


// This should return 4, and it indeed returns 4
console.log(   findMissing([1,2,3,5])   );


// This should return 'undefined', but it returns 3
console.log(   findMissing([1,2,3,4])   );


// This should return 5, and it indeed returns 5
console.log(   findMissing([2,3,4,6])   );

UPDATE 1:

Based on the answers below, the following code delivers the desired outcome using the reduce() method:

// ****SOLUTION:****
function findMissing2(arr) {
  return arr.reduce(function(prev, curr, index, array) {
    if (curr === index + array[0]) {
      return prev;
    } else {
      return index + array[0]++;
    }
  }, void 0);
}

console.log(   findMissing2([1,2,3,4])   ); // Undefined
console.log(   findMissing2([1,2,3,5])   ); // 4
console.log(   findMissing3([2,3,4,6])   ); // 5
console.log(   findMissing2([2,3,4,5])   ); // Undefined
console.log(   findMissing2([2,4,5,6])   ); // 3

Your reduce closure/callback function needs to return the value to be used as the next prev in the next iteration.

Because of this, in the second example, the first iteration returns undefined , as it does not enter the if block. The second iteration is passed the parameters of undefined, 3 , where undefined - 3 !== 1 so it returns 2.

This propagates the way up your iterations, until it returns 3.

As such, I'm struggling to think of a way your reduce function could be adapted to correct this.

Perhaps using a simple for loop might be a bit more robust?

function findMissing(arr) {
   for(var i = 1; i < arr.length; i++) {
       if(arr[i] - arr[i-1] !== 1) {
           return arr[i]-1;
       }
   }
}

Instead of reduce you should use for loop here

 function findMissing(arr) { var r = []; for (var i = arr[0]; i <= arr[arr.length - 1]; i++) { if (arr.indexOf(i) == -1) r.push(i); } return r; } console.log(findMissing([1, 2, 3, 5])); console.log(findMissing([1, 3, 6])); console.log(findMissing([10, 13, 16]));

I would do this job as follows;

 var a1 = [1,2,3,5], a2 = [2,3,4,5], a3 = [2,4,5,6], res1 = a1.reduce((p,c,i,a) => c == i+a[0] ? p : i + a[0]++, void 0), res2 = a2.reduce((p,c,i,a) => c == i+a[0] ? p : i + a[0]++, void 0), res3 = a3.reduce((p,c,i,a) => c == i+a[0] ? p : i + a[0]++, void 0); console.log(res1); console.log(res2); console.log(res3);

Note: void 0 is a very safe undefined value in JS. The above code will mutate the tested array. You might prefer to call like a1.slice().reduce... if you want to keep the tested array as it is.

As I said in comments, if you are looking for efficiency you could do it with recursion:

function findMissing(arr) {
    if (arr.length === 1) return;
    if(arr[1] - arr[0] !== 1){
        return arr[0];
    }
    else{
        return findMissing(arr.slice(1,arr.length));
    }
}

Or even with a while loop:

function findMissing(arr) {
    var i = 0;
    while (arr[i+1] - arr[i] === 1) {
        i++;
    }
    if (i < arr.length-1) return arr[i];
}
 var findMissing = function (list) {  
           var expected_sum = (list[0] + list[list.length - 1]) * (list.length + 1) / 2;
           var sum = list.reduce((a,b)=>a+b);
           return expected_sum - sum;
         }
          
          console.log(findMissing([-5,-1,1,3,5,7,9,11]))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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