Count pairs in an array in JavaScript - javascript

I'm still a junior at web dev and I am trying to solve this problem.
I have to find the number of matching pairs in these arrays:
var ar1 = [10, 20, 20, 10, 10, 30, 50, 10, 20] // return 3 (2 pairs of 10 and 1 pair of 20)
var ar2 = [1, 1, 3, 1, 2, 1, 3, 3, 3, 3] // return 4 (2 pairs of 1 and 2 pairs of 3)
// I started to write my logic below but I'm stuck, could you please help me to solve this problem ?
// The last result I am returning is a filtered array with all the nbs that are superior to 1 and then can't figure out how to get the result of matching pairs :-(
function countPairs(n, ar) {
const count = {};
ar.forEach((nb) => (count[nb] = (count[nb] || 0) + 1));
const values = Object.values(count);
const filter = values.filter((value) => value > 1);
return filter;
}
// 9 and 10 are the length of the arrays
console.log(countPairs(9, ar1))
console.log(countPairs(10, ar2))
Thank you very much for your help!

Perhaps there is a faster/better way to calculate this than this O(2n) solution, but it's something:
var ar1 = [10, 20, 20, 10, 10, 30, 50, 10, 20] // return 3 (2 pairs of 10 and 1 pair of 20)
var ar2 = [1, 1, 3, 1, 2, 1, 3, 3, 3, 3] // return 4 (2 pairs of 1 and 2 pairs of 3)
function countPairs(ar) {
var obj = {};
ar.forEach(item => {
obj[item] = obj[item] ? obj[item] + 1 : 1;
});
return Object.values(obj).reduce((acc, curr) => {
acc += Math.floor(curr / 2)
return acc;
}, 0);
}
console.log(countPairs(ar1))
console.log(countPairs(ar2))
This first calculates the number of occurences for each number and stores them in an Object. Once that is done, we reduce over the values and return the quotient from the division with 2 (to get the number of pairs in total).
Note: I removed the first argument from your function, because the array length is not needed as an argument. It can be obtained from the array you pass directly.

We can achieve this in O(n) time. Maintain an object which keeps track whether a number have been found before, if it was found before, then it makes up a pair, so we increment the pairs count. If not we make the entry of that number in the object 1
function countPairs(arr) {
let pairs = 0;
const obj = {};
arr.forEach(i => {
if (obj[i]) {
pairs += 1;
obj[i] = 0;
} else {
obj[i] = 1;
}
});
return pairs;
}

Simplest solution I can find:
create empty dictionary var t = {}; and use it to count each item in array arr.forEach (i => t[i] = (t[i] || 0) + 1);. After that take all keys Object.values(t) and sum .reduce((acc, p) => acc + ..., 0) each item counts divided by 2 p/2 with Int semantics of course Math.floor(...).
function countPairs(arr) {
var t = {};
arr.forEach (i => t[i] = (t[i] || 0) + 1);
return Object.values(t).reduce((acc, p) => acc + Math.floor(p/2), 0);
}
console.dir(countPairs([1,2,2,2,2,3]));
console.dir(countPairs([1,2,2,2,2,2,3]));
console.dir(countPairs([1,2,2,2,2,2,2,3]));
console.dir(countPairs([10, 20, 20, 10, 10, 30, 50, 10, 20]));
console.dir(countPairs([1, 1, 3, 1, 2, 1, 3, 3, 3, 3]));
First argument in your implementation is not necessary.
Please up-vote if answer was helpful

Concise approach with reduce method
const countPairs = arr => (pairs = [], arr.reduce((p, c) => (p[c] ? (pairs.push([p[c], c]), delete p[c]) : p[c] = c, p), {}), pairs.length)
console.log(countPairs([10, 20, 20, 10, 10, 30, 50, 10, 20]));

So, I wanted a more simpler solution to this problem since I'm just starting to learn to code and I'm teaching my self. I found this solution works perfectly for what you want. I didn't created this solution I found it on the internet(https://www.geeksforgeeks.org/count-equal-element-pairs-in-the-given-array/) I just translated it to JavaScript.
function countDuplicates(n, arr) {
var count = 0;
arr.sort();
for (var i = 0; i < n;) {
if (arr[i] === arr[i + 1]) {
count++;
i = i + 2;
} else {
i++;
}
}
return count;
}
console.log(countDuplicates(9, [10, 20, 20, 10, 10, 30, 50, 10, 20]));

There are some more concise answers here, but here's the solution I have for you:
function countDuplicates(arr) {
var counts = {}, sum = 0;
for (var i = 0; i < arr.length; i++) {
counts[arr[i].toString()] = (counts[arr[i].toString()] || 0) + 1;
}
for (var count in counts) {
if (Object.prototype.hasOwnProperty.call(counts, count)) sum += Math.floor(counts[count] / 2);
}
return sum;
}
console.log(countDuplicates([10, 20, 20, 10, 10, 30, 50, 10, 20]));

I hope I have helped
function numberOfPairs(array) {
let arr = [...array].sort();
let result = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i] == arr[i + 1]) {
result++;
arr.shift();
}
}
console.log(result);
}
numberOfPairs(['blue', 'blue', 'blue', 1, 2, 5, 2, 1]);

Related

Sum of similar value in n X n dimensional array with n^2 complexity

Given an array [[1, 7, 3, 8],[3, 2, 9, 4],[4, 3, 2, 1]],
how can I find the sum of its repeating elements? (In this case, the sum would be 10.)
Repeated values are - 1 two times, 3 three times, 2 two times, and 4 two times
So, 1 + 3 + 2 + 4 = 10
Need to solve this problem in the minimum time
There are multiple ways to solve this but time complexity is a major issue.
I try this with the recursion function
How can I optimize more
`
var uniqueArray = []
var sumArray = []
var sum = 0
function sumOfUniqueValue (num){
for(let i in num){
if(Array.isArray(num[i])){
sumOfUniqueValue(num[i])
}
else{
// if the first time any value will be there then push in a unique array
if(!uniqueArray.includes(num[i])){
uniqueArray.push(num[i])
}
// if the value repeats then check else condition
else{
// we will check that it is already added in sum or not
// so for record we will push the added value in sumArray so that it will added in sum only single time in case of the value repeat more then 2 times
if(!sumArray.includes(num[i])){
sumArray.push(num[i])
sum+=Number(num[i])
}
}
}
}
}
sumOfUniqueValue([[1, 7, 3, 8],[1, 2, 9, 4],[4, 3, 2, 7]])
console.log("Sum =",sum)
`
That's a real problem, I am just curious to solve this problem so that I can implement it in my project.
If you guys please mention the time it will take to complete in ms or ns then that would be really helpful, also how the solution will perform on big data set.
Thanks
I would probably use a hash table instead of an array search with .includes(x) instead...
And it's also possible to use a classical for loop instead of recursive to reduce call stack.
function sumOfUniqueValue2 (matrix) {
const matrixes = [matrix]
let sum = 0
let hashTable = {}
for (let i = 0; i < matrixes.length; i++) {
let matrix = matrixes[i]
for (let j = 0; j < matrix.length; j++) {
let x = matrix[j]
if (Array.isArray(x)) {
matrixes.push(x)
} else {
if (hashTable[x]) continue;
if (hashTable[x] === undefined) {
hashTable[x] = false;
continue;
}
hashTable[x] = true;
sum += x;
}
}
}
return sum
}
const sum = sumOfUniqueValue2([[1, 7, 3, 8],[[[[[3, 2, 9, 4]]]]],[[4, 3, 2, 1]]]) // 10
console.log("Sum =", sum)
This is probably the fastest way...
But if i could choose a more cleaner solution that is easier to understand then i would have used flat + sort first, chances are that the built in javascript engine can optimize this routes instead of running in the javascript main thread.
function sumOfUniqueValue (matrix) {
const numbers = matrix.flat(Infinity).sort()
const len = numbers.length
let sum = 0
for (let i = 1; i < len; i++) {
if (numbers[i] === numbers[i - 1]) {
sum += numbers[i]
for (i++; i < len && numbers[i] === numbers[i - 1]; i++);
}
}
return sum
}
const sum = sumOfUniqueValue2([[1, 7, 3, 8],[[[[[3, 2, 9, 4]]]]],[[4, 3, 2, 1]]]) // 10
console.log("Sum =", sum)
You could use an objkect for keeping trak of seen values, like
seen[value] = undefined // value is not seen before
seen[value] = false // value is not counted/seen once
seen[value] = true // value is counted/seen more than once
For getting a value, you could take two nested loops and visit every value.
Finally return sum.
const
sumOfUniqueValue = (values, seen = {}) => {
let sum = 0;
for (const value of values) {
if (Array.isArray(value)) {
sum += sumOfUniqueValue(value, seen);
continue;
}
if (seen[value]) continue;
if (seen[value] === undefined) {
seen[value] = false;
continue;
}
seen[value] = true;
sum += value;
}
return sum;
},
sum = sumOfUniqueValue([[1, 7, 3, 8], [3, 2, 9, 4], [4, 3, 2, 1]]);
console.log(sum);
Alternatively take a filter and sum the values. (it could be more performat with omitting same calls.)
const
data = [[1, 7, 3, 8], [3, 2, 9, 4, 2], [4, 3, 2, 1]],
sum = data
.flat(Infinity)
.filter((v, i, a) => a.indexOf(v) !== a.lastIndexOf(v) && i === a.indexOf(v))
.reduce((a, b) => a + b, 0);
console.log(sum);
You can flatten the array, filter-out single-instance values, and sum the result:
const data = [
[ 1, 7, 3, 8 ],
[ 3, 2, 9, 4 ],
[ 4, 3, 2, 1 ]
];
const numbers = new Set( data.flat(Infinity).filter(
(value, index, arr) => arr.lastIndexOf(value) != index)
);
const sum = [ ...numbers ].reduce((a, b) => a + b, 0);
Another approach could be the check the first and last index of the number in a flattened array, deciding whether or not it ought to be added to the overall sum:
let sum = 0;
const numbers = data.flat(Infinity);
for ( let i = 0; i < numbers.length; i++ ) {
const first = numbers.indexOf( numbers[ i ] );
const last = numbers.lastIndexOf( numbers[ i ] );
if ( i == first && i != last ) {
sum = sum + numbers[ i ];
}
}
// Sum of numbers in set
console.log( sum );

Find the sum of the first n num [duplicate]

This question already has answers here:
Javascript - Counting array elements by reduce method until specific value occurs doesn't give a correct output
(4 answers)
Closed 2 years ago.
I have an array with numbers. Find the sum of the first N elements to the first zero. Task must be completed with
Example: - summarize the first 3 elements, because next is the element with the number 0.
You could do this as follows:
let arr = [10, 20, 3, 0, 16, 35, 1];
let sum = arr.slice(0, arr.indexOf(0)).reduce((sum, v) => sum + v);
console.log(sum);
I first extract the numbers in front of the first zero using Array.slice(). Then I use Array.reduce() to compute the sum of these numbers.
You can not break the iteration of reduce(). You can use a flag variable based on which you can add value to sum.
Try the following way:
let arr = [10, 20, 3, 0, 16, 35, 1];
let flag = true;
let sumNum = arr.reduce((sum, elem) => {
if (elem == 0) {
flag = false;
};
if(flag) return sum + elem;
else return sum + 0;
}, 0)
console.log(sumNum)
You can utilize an external variable stopCounting to flag if the counting should continue or not.
let arr = [10, 20, 3, 0, 16, 35, 1];
let stopCounting = false;
let sumNum = arr.reduce((sum, elem) => {
if (elem == 0) {
stopCounting = true;
}
return stopCounting ? sum : sum + elem;
}, 0);
console.log(sumNum);
You could iterate with a short circuit and check the value and add the value if not zero.
This approach does not search for zero in advance and needs only a single loop in the worst case.
var array = [10, 20, 3, 0, 16, 35, 1],
sum = 0;
array.every(v => (sum += v, v));
console.log(sum);
const arr = [10, 20, 3, 0, 16, 35, 1];
const zeroIndex = arr.indexOf(0);
const total = arr.slice(0, zeroIndex > 0 ? zeroIndex : arr.length)
.reduce(sum, n => sum+n, 0);
console.log(total);

How can I return only the number of matching pair values in array?

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]))
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
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).
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
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

To find minimum elements in array which has sum equals to given value

I am trying to find out the minimum elements in array whose sum equals
the given input.I tried for few input sum but was able to find only a
pair in first case while I need to implement for more than just a pair.
var arr = [10, 0, -1, 20, 25, 30];
var sum = 45;
var newArr = [];
console.log('before sorting = ' + arr);
arr.sort(function(a, b) {
return a - b;
});
console.log('after sorting = ' + arr);
var l = 0;
var arrSize = arr.length - 1;
while (l < arrSize) {
if (arr[l] + arr[arrSize] === sum) {
var result = newArr.concat(arr[l], arr[arrSize]);
console.log(result);
break;
} else if (arr[l] + arr[arrSize] > sum) {
arrSize--;
} else {
l++;
}
}
Input Array : [10, 0, -1, 20, 25, 30]
Required Sum: 45
Output: [20, 25]
I am trying for
Required Sum : 59
Output: [10, -1, 20, 30]
This can be viewed as an optimization problem which lends itself well to dynamic programming.
This means you would break it up into a recursion that tries to find the minimum length of increasingly smaller arrays with the sum adjusted for what's been removed. If your array is [10, 0, -1, 20, 25, 30] with a sum of 59 you can think of shortest as the min of:
[10, ... shortest([ 0, -1, 20, 25, 30], 49)
[0, ... shortest([10, 20, 25, 30], 49), 59)
[-1, ... shortest([10, 0, 20, 25, 30], 60)
... continue recursively
with each recursion, the array gets shorter until you are left with one element. Then the question is whether that element equals the number left over after all the subtractions.
It's easier to show in code:
function findMinSum(arr, n){
if(!arr) return
let min
for (let i=0; i<arr.length; i++) {
/* if a number equals the sum, it's obviously
* the shortest set, just return it
*/
if (arr[i] == n) return [arr[i]]
/* recursively call on subset with
* sum adjusted for removed element
*/
let next = findMinSum(arr.slice(i+1), n-arr[i])
/* we only care about next if it's shorter then
* the shortest thing we've seen so far
*/
if (next){
if(min === undefined || next.length < min.length){
min = [arr[i], ...next]
}
}
}
return min && min /* if we found a match return it, otherwise return undefined */
}
console.log(findMinSum([10, 0, -1, 20, 25, 30], 59).join(', '))
console.log(findMinSum([10, 0, -1, 20, 25, 30], 29).join(', '))
console.log(findMinSum([10, 0, -1, 20, 25, 30], -5)) // undefined when no sum
This is still pretty computationally expensive but it should be much faster than finding all the subsets and sums.
One option is to find all possible subsets of the array, and then filter them by those which sum to the required value, and then identify the one(s) with the lowest length:
const getMinElementsWhichSum = (arr, target) => {
const subsets = getAllSubsetsOfArr(arr);
const subsetsWhichSumToTarget = subsets.filter(subset => subset.reduce((a, b) => a + b, 0) === target);
return subsetsWhichSumToTarget.reduce((a, b) => a.length < b.length ? a : b, { length: Infinity });
};
console.log(getMinElementsWhichSum([10, 0, -1, 20, 25, 30], 45));
console.log(getMinElementsWhichSum([10, 0, -1, 20, 25, 30], 59));
// https://stackoverflow.com/questions/5752002/find-all-possible-subset-combos-in-an-array
function getAllSubsetsOfArr(array) {
return new Array(1 << array.length).fill().map(
(e1,i) => array.filter((e2, j) => i & 1 << j));
}
Try this,
var arr = [10, 0, -1, 20, 25, 30];
var sum = 29;
var newArr = [];
var sum_expected = 0;
var y = 0;
while (y < arr.length) {
for (let i = 0; i < arr.length; i++) {
var subArr = [];
sum_expected = arr[i];
if (arr[i] != 0) subArr.push(arr[i]);
for (let j = 0; j < arr.length; j++) {
if (i == j)
continue;
sum_expected += arr[j];
if (arr[j] != 0) subArr.push(arr[j]);
if (sum_expected == sum) {
var result = arr.filter((el)=>(subArr.indexOf(el) > -1));
!newArr.length ? newArr = result : result.length < newArr.length ? newArr = result : 1;
break;
}
}
}
let x = arr.shift();
arr.push(x);
y++;
}
if (newArr.length) {
console.log(newArr);
} else {
console.log('Not found');
}

Find Missing Numbers from Unsorted Array

I found this JavaScript algorithm excercise:
Question:
From a unsorted array of numbers 1 to 100 excluding one number, how will you find that number?
The solution the author gives is:
function missingNumber(arr) {
var n = arr.length + 1,
sum = 0,
expectedSum = n * (n + 1) / 2;
for (var i = 0, len = arr.length; i < len; i++) {
sum += arr[i];
}
return expectedSum - sum;
}
I wanted to try and make it so you can find multiple missing numbers.
My solution:
var someArr = [2, 5, 3, 1, 4, 7, 10, 15]
function findMissingNumbers(arr) {
var missingNumbersCount;
var missingNumbers = [];
arr.sort(function(a, b) {
return a - b;
})
for(var i = 0; i < arr.length; i++) {
if(arr[i+1] - arr[i] != 1 && arr[i+1] != undefined) {
missingNumbersCount = arr[i+1] - arr[i] - 1;
for(j = 1; j <= missingNumbersCount; j++) {
missingNumbers.push(arr[i] + j)
}
}
}
return missingNumbers
}
findMissingNumbers(someArr) // [6, 8, 9, 11, 12, 13, 14]
Is there a better way to do this? It has to be JavaScript, since that's what I'm practicing.
You could use a sparse array with 1-values at indexes that correspond to values in the input array. Then you could create yet another array with all numbers (with same length as the sparse array), and retain only those values that correspond to an index with a 1-value in the sparse array.
This will run in O(n) time:
function findMissingNumbers(arr) {
// Create sparse array with a 1 at each index equal to a value in the input.
var sparse = arr.reduce((sparse, i) => (sparse[i]=1,sparse), []);
// Create array 0..highest number, and retain only those values for which
// the sparse array has nothing at that index (and eliminate the 0 value).
return [...sparse.keys()].filter(i => i && !sparse[i]);
}
var someArr = [2, 5, 3, 1, 4, 7, 10, 15]
var result = findMissingNumbers(someArr);
console.log(result);
NB: this requires EcmaScript2015 support.
The simplest solution to this problem
miss = (arr) => {
let missArr=[];
let l = Math.max(...arr);
let startsWithZero = arr.indexOf(0) > -1 ? 0 : 1;
for(i = startsWithZero; i < l; i++) {
if(arr.indexOf(i) < 0) {
missArr.push(i);
}
}
return missArr;
}
miss([3,4,1,2,6,8,12]);
Something like this will do what you want.
var X = [2, 5, 3, 1, 4, 7, 10, 15]; // Array of numbers
var N = Array.from(Array(Math.max.apply(Math, X)).keys()); //Generate number array using the largest int from X
Array.prototype.diff = function(a) {
return this.filter(function(i) {return a.indexOf(i) < 0;}); //Return the difference
};
console.log(N.diff(X));
Option 1:
1. create a binary array
2. iterate over input array and for each element mark binary array true.
3. iterate over binary array and find out numbers of false.
Time complexity = O(N)
Space complexity = N
Option 2:
Sort input array O(nLogn)
iterate over sorted array and identify missing number a[i+1]-a[i] > 0
O(n)
total time complexity = O(nlogn) + O(n)
I think the best way to do this without any iterations for a single missing number would be to just use the sum approach.
const arr=[1-100];
let total=n*(n+1)/2;
let totalarray=array.reduce((t,i)=>t+i);
console.log(total-totalarray);
You can try this:
let missingNum= (n) => {
return n
.sort((a, b) => a - b)
.reduce((r, v, i, a) =>
(l => r.concat(Array.from({ length: v - l - 1 }, _ => ++l)))(a[i - 1]),
[]
)
}
console.log(missingNum([1,2,3,4,10]));
Solution to find missing numbers from unsorted array or array containing duplicate values.
Array.prototype.max = function() {
return Math.max.apply(null, this);
};
var array1 = [1, 3, 4, 7, 9];
var n = array1.length;
var totalElements = array1.max(); // Total count including missing numbers. Can use max
var d = new Uint8Array(totalElements)
for(let i=0; i<n; i++){
d[array1[i]-1] = 1;
}
var outputArray = [];
for(let i=0; i<totalElements; i++) {
if(d[i] == 0) {
outputArray.push(i+1)
}
}
console.log(outputArray.toString());
My solution uses the same logic as trincot's answer
The time complexity is O(n)
const check_miss = (n) => {
let temp = Array(Math.max(...n)).fill(0);
n.forEach((item) => (temp[item] = 1));
const missing_items = temp
.map((item, index) => (item === 0 ? index : -1))
.filter((item) => item !== -1);
console.log(missing_items);
};
n = [5, 4, 2, 1, 10, 20, 0];
check_miss(n);

Categories

Resources