enoent
enoent

Reputation: 83

Extract duplicate values with number of occurrences for JS Array

For example we have an array

const nums = [1,1,8,12,2,3,3,3,7];

If I want to map number of occurrences of each array member I could use something like

function extractDupes(arr) {
  return arr.reduce(function (acc, item) { 
    if (item in acc) {
      acc[item]++
    }
    else {
      acc[item] = 1
    }
    return acc
  }, {})
}

This would return object like

{ '1': 2, '2': 1, '3': 3, '7': 1, '8': 1, '12': 1 }

Is there an optimal way to filter out numbers which are showing up more than once just with using reduce (in a single pass) and have just

{ '1': 2, '3': 3 }

Upvotes: 1

Views: 226

Answers (6)

Kharel
Kharel

Reputation: 827

It has been answered and accepted but anyhow here is how i would do.

const nums = [1, 1, 8, 12, 2, 3, 3, 3, 7];

const map = nums.reduce((acc, num) => {
  acc.frequency[num] = (acc.frequency[num] || 0) + 1;

  if (acc.frequency[num] > 1) {
    acc.replicates[num] = acc.frequency[num];
  }

  return acc;
}, { frequency: {}, replicates: {} });

console.log(map);

Upvotes: 0

Pedro Lima
Pedro Lima

Reputation: 1606

const nums = [1,1,8,12,2,3,3,3,7];
const dups = {};
nums.forEach((v, i, s) => {
  if (s.indexOf(v) != i)
    if (dups[v])
      dups[v]++;
    else
      dups[v] = 2;
});

console.log(dups);

If you also want the array of unique values at the end:

const nums = [1,1,8,12,2,3,3,3,7];
const dups = {};
const uniques = nums.filter((v, i, s) => {
  if (s.indexOf(v) != i)
    if (dups[v])
      dups[v]++;
    else
      dups[v] = 2;
  else
    return true;
});

console.log(dups);
console.log(uniques);

Upvotes: 2

Ian Swift
Ian Swift

Reputation: 69

let arrAssist = [];

array.sort();
arrAssist.push(inventory[0]);
for(var i = 1; i < array.length; i++){
  if(array[i] != array[i - 1]){
    arrAssist.push(array[i]);
  }
}

in this example, arrAssist contains the array with no duplicates

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386634

You could take a nested property for the final object.

function extractDupes(array) {
    return array
        .reduce(function(acc, item) {
            if (acc[item]) acc.dupes[item] = (acc.dupes[item] || 1) + 1;
            else acc[item] = true;
            return acc;
         }, { dupes: {} })
        .dupes;
}

const nums = [1, 1, 8, 12, 2, 3, 3, 3, 7];

console.log(extractDupes(nums))

Upvotes: 1

Chris
Chris

Reputation: 2806

have a staging variable for values equaling 1 and promote them to the main result when they're hit the second time?

const nums = [1,1,8,12,2,3,3,3,7];

function extractDupes(arr) {
  const staging = {}
  return arr.reduce(function (acc, item) { 
    if (item in acc) {
      acc[item]++
    } else if(item in staging) {
      acc[item] = 2
      delete staging[item]
    } else {
      staging[item] = 1
    }
    return acc
  }, {})
}

document.getElementById('hi').innerHTML = JSON.stringify(extractDupes(nums))
<div id="hi"></div>

Upvotes: 1

hgb123
hgb123

Reputation: 14891

You could use Object.entries to transform the object to key-value pairs then filter the pair that have value greater than 1, and then transform the pairs back to object by Object.fromEntries

const nums = [1, 1, 8, 12, 2, 3, 3, 3, 7]

function extractDupes(arr) {
  return Object.fromEntries(
    Object.entries(
      arr.reduce(function (acc, item) {
        if (item in acc) {
          acc[item]++
        } else {
          acc[item] = 1
        }
        return acc
      }, {})
    ).filter(([key, value]) => value > 1)
  )
}

console.log(extractDupes(nums))

Upvotes: 0

Related Questions