14

Say I found a box of loose shoes (all the same kind) at a garage sale, and I've created an array with each individual shoe listed by shoe size.

I want to display the number of paired values of shoe sizes in the array. For example, I have this array:

[10,10,10,10,20,20,20,30,50]

I would like to display 3 because we have 3 pairs of numbers:

10,10
10,10
20,20

And 3 remaining values that don't have a matching pair-value (20,30,50).

How can I do this?

function pairNumber(arr) {
  var sorted_arr = arr.sort();
  var i;
  var results = [];
  for (i = 0; i < sorted_arr.length; i++) {
    if (sorted_arr[i + 1] == sorted_arr[i]) {
      results.push(sorted_arr[i]);
    }

  }
  return results.length;
}
console.log(pairNumber([10, 10, 10, 10, 20, 20, 20, 30, 50]))
TylerH
  • 20,799
  • 66
  • 75
  • 101
Diasline
  • 625
  • 3
  • 32

4 Answers4

14

Here is another approach using a Set:

function pairNumbers(arr) {
  let count = 0;
  const set = new Set();

  for (let i = 0; i < arr.length; i++) {
    if (set.delete(arr[i])) {
      count++;
    } else {
      set.add(arr[i])
    }
  }

  return count;
}
console.log(pairNumbers([10, 10, 10, 10, 20, 20, 20, 30, 50])) // 3
Matt Aft
  • 8,742
  • 3
  • 24
  • 37
8

I'd reduce into an object, counting up the number of occurrences of each number. Then reduce again on the Object.values of the object to count up the number of pairs, adding Math.floor(count / 2) to the accumulator on each iteration:

function pairNumber(arr) {
  const itemCounts = arr.reduce((a, item) => {
    a[item] = (a[item] || 0) + 1;
    return a;
  }, {});
  return Object.values(itemCounts)
    .reduce((pairsSoFar, count) => pairsSoFar + Math.floor(count / 2), 0);
}
console.log(pairNumber([10, 10, 10, 10, 20, 20, 20, 30, 50]))

Probably better to avoid .sort if possible - that increases the computational complexity from O(n) (minimum) to O(n log n).

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • I wonder if building `itemCounts` doesn't add the same `O(nlogn)` back? How do objects work under the hood? Hashtables? Balanced trees? – Vilx- Sep 07 '19 at 21:49
  • For any remotely sane implementation, it'll be `O(1)`, luckily: https://stackoverflow.com/questions/7700987/performance-of-key-lookup-in-javascript-object . If using an object causes an issue, could use a Map instead – CertainPerformance Sep 07 '19 at 21:50
0

If I understood the question well then this can be simplified even further by relying on sort initially...

Increment i to the next position after finding the pair and let the for loop increment it once again.

 function pairNumber(arr) {
    const sorted_arr = [...arr].sort(); // disallowing array mutation
    let cnt = 0;
    for (let i = 0; i < sorted_arr.length; i++) {
      if (sorted_arr[i + 1] === sorted_arr[i]) {
        cnt++;
        i = i + 1;
      }

    }
    return cnt;
  }
  console.log(pairNumber([10, 10, 10, 10, 10, 20, 20, 20, 20, 30, 30, 50]))
  // 5 --> 2 pairs of 10, 2 pairs of 20, 1 pair of 30
  console.log(pairNumbers([10, 10, 10, 10, 20, 20, 20, 30, 50])) 
  // 3 --> 2 pairs of 10 one pair of 20
EugenSunic
  • 13,162
  • 13
  • 64
  • 86
  • 1
    I believe `sort` will mutate the original array, so a side-effect would be that the array being passed in will be sorted after calling this function. – Matt Aft Sep 07 '19 at 23:06
0

Many thanks to all guys that help me understand more how to solve this issue. After studying the answers in the post I come up with my own solution.

Thanks to you I understand I should increment i at the end of if to prevent a repetitive comparison.

function pairNumbers(arr) {
  const sorted_arr = arr.sort();
  const results = [];
  for (let i = 0; i < sorted_arr.length; i++) {
    if (sorted_arr[i] == sorted_arr[i + 1]) {
      results.push(sorted_arr[i]);
      i = i + 1; 
    }
  }
  return results.length;
}
console.log(pairNumbers([10, 10, 10, 10, 20, 20, 20, 30, 50])) // 3
peterSO
  • 158,998
  • 31
  • 281
  • 276
Diasline
  • 625
  • 3
  • 32