Using reduce to delete even numbers in an object - javascript

I'm given an array of numbers. I have created an object named counts, whose keys are the numbers and values the amount of times those numbers appear in the array. Can't work out how to use reduce to delete the even counts of the numbers.
A = [ 20, 1, -1, 2, -2, 3, 3, 5, 5, 1, 2, 4, 20, 4, -1, -2, 5 ]
n = 5
function findOdd(A) {
let counts = {};
for (let i = 0; i < A.length; i++) {
let num = A[i];
counts[num] = counts[num] ? counts[num] + 1 : 1;
}
//counts -> { '1': 2, '2': 2, '3': 2, '4': 2, '5': 3, '20': 2, '-1': 2, '-2': 2 }
const answer = Object.keys(counts).reduce((object, key) => {
if (key % 2 !== 0) {
object[key] = counts[key];
}
return object;
}, {})
return answer;
Must return the key of the odd count.
SOLUTION:
function findOdd(A) {
const counts = {};
for (let i = 0; i < A.length; i++) {
let num = A[i];
counts[num] = counts[num] ? counts[num] + 1 : 1;
}
Object.keys(counts).forEach(key => {
if(counts[key] % 2 === 0) {
delete counts[key];
}
});
return Number(Object.keys(counts));
}

You can make use of Object.entries to obtain entires, then filter entries whose values are odd, and then reconstruct new Object from those entries using Object.fromEntries:
const countObject = { '1': 2, '2': 2, '3': 2, '4': 2, '5': 3, '20': 2, '-1': 2, '-2': 2 };
const oddEntries = Object.entries(countObject).filter(([key, value]) => value % 2 !== 0);
const oddCountObject = Object.fromEntries(oddEntries)
console.log(oddCountObject)

function findOdd(arr) {
const counts = {}; // `const` declared objects/arrays are not immutable
for(let i = 0; i < arr.length; i++) {
counts[arr[i]] = counts[arr[i]] || 0;
counts[arr[i]]++;
}
Object.keys(counts).forEach(key => {
if(counts[key] % 2 === 0) {
delete counts[key];
}
});
return counts;
}
const array = [1, 2, 3, 4, 5, 6, 1, 1, 4, 5, 4, 9];
// 1:3, 2:1, 3:1, 4:3, 6:1, 9:1
// Does not show a `5` key due to there being an even number of fives in `array`
console.log(findOdd(array));
Yes, I know delete is inefficient, but that shouldn't matter, unless it is a requirement for being quick. I believe you can just set counts[key] = undefined or counts[key] = null, you can see the benchmarks here

I know there are already great answers but as the question said "using reduce" I thought it'd be fun to try doing this using only reduce:
const findOdd = arr => arr.reduce((acc, d, i, list) => {
if (!acc[d]) {
acc[d] = 0;
}
acc[d]++;
if (i === list.length - 1) {
return Object.keys(acc)
.reduce((subAcc, key) => ({
...subAcc,
...(acc[key] % 2 === 0 ? {} : {
[key]: acc[key]
})
}), {})
}
return acc;
}, {})

Related

Chunk an array of objects and add empty arrays at the end

I need to chunk an array of objects so i write:
function conditionalChunk(array, size, rules = {}) {
let copy = [...array],
output = [],
i = 0;
while (copy.length)
output.push(copy.splice(0, rules[i++] ?? size))
return output
}
and it works fine if I have rules like { 0: 2, 1: 2 }
const input = [[1,2,3],[4,5,6,7]],
output = conditionalChunk(input.flat(), 3, { 0: 2, 1: 2 });
// OUTPUT: [[1,2],[3,4],[5,6,7]]
but when I have rules at the end like { 0: 2, 1: 2, 2:0, 5:0 } my function ignore to create empty arrays at the end.
the output I need is:
const input = [[1,2,3],[4,5,6,7]],
output = conditionalChunk(input.flat(), 3, { 0: 2, 1: 2, 2:0, 5:0 });
// OUTPUT: [[1,2],[3,4],[],[5,6,7],[]]
so I just need to not ignore rules for empty arrays at the end of array. How I can do that?
Finally, you could check the keys of rules and if greater or equal to the next index of output push an empty array.
function conditionalChunk(array, size, rules = {}) {
let output = [],
i = 0;
while (i < array.length)
output.push(array.slice(i, i += rules[output.length] ?? size));
let l = Object.keys(rules).reduce((l, v) => l + (v >= output.length), 0);
while (l--) output.push([]);
return output;
}
console.log(conditionalChunk([1, 2, 3, 4, 5, 6, 7], 3, { 0: 2, 1: 2 })); // [[1,2],[3,4],[5,6,7]]
console.log(conditionalChunk([1, 2, 3, 4, 5, 6, 7], 3, { 0: 2, 1: 2, 2: 0, 5: 0 })); // [[1,2],[3,4],[],[5,6,7],[]]
console.log(conditionalChunk([1, 2, 3, 4, 5, 6, 7], 3, { 0: 0, 1: 2, 8: 0, 7: 0, 9:0, 20:0 }));
.as-console-wrapper { max-height: 100% !important; top: 0; }
maybe you can try this, I prefer for...each loop in place of a while.
function conditionalChunk(array, size = 1, rules = {}) {
let copy = [...array],
output = [],
i = 0;
for (const rule of Object.keys(rules)) {
let val = copy.splice(0, rules[rule] || size);
if (typeof val === 'undefined') val = [];
output.push(val);
}
return output;
}
var results = conditionalChunk([1, 2, 3, 4, 5], 2, { 0:2, 1: 2, 2:2, 3:0 });
console.log(results, '::results::');
https://jsfiddle.net/5ozbj7na/
A solution to your problem would be to add this bit of code after the while loop before the return statement
output.length = Math.max.apply(null, [output.length, ...Object.keys(rules)]) || output.length;
for (r in rules)
{
output[r] = new Array(rules[r]);
}
It just extends the output array to the desired length then populates required spots with empty arrays (sorry for the complicated first line but JavaScript is complicated so :| ...)
Please try this one, this should work for you and is done based on your solution, so it should be easier to understand
function conditionalChunk(array, size, rules = {}) {
let copy = [...array],
output = [],
i = 0;
while (copy.length) output.push(copy.splice(0, rules[i++] ?? size));
const arr = Object.keys(rules).filter((key) => key > i);
arr.forEach((key) => {
if (rules[key] === 0) output.push([]);
});
return output;
}

how to find unique value from the array?

I want to find unique value and put that in new array. I have below array:
My code:
var arr = [1,1,1,1,2,2,2,2,3,3,3,5,5,5];
const countUnique = arr => {
const counts = {};
for (var i = 0; i < arr.length; i++) {
counts[arr[i]] = (counts[arr[i]] || 0) + 1;
};
return counts;
};
console.log(countUnique(arr));
Result: { '1': 4, '2': 4, '3': 3, '5': 3 }
I want to display unique value like Expected Output:
41423335
Hope you understand what I want. but I want to know what's the best way?
You can reduce the counts object's entries to a string, and then convert the string to a number using unary +:
const countUnique = arr => {
const counts = {};
for (var i = 0; i < arr.length; i++) {
counts[arr[i]] = (counts[arr[i]] || 0) + 1;
};
return +Object.entries(counts)
.reduce((acc, [k, v]) => `${acc}${v}${k}`, '');
};
const arr = [1,1,1,1,2,2,2,2,3,3,3,5,5,5];
console.log(countUnique(arr));
You could take a string with digits and replace with the wanted length and digit.
const
values = [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 5, 5, 5],
result = +values
.join('')
.replace(/(.)\1*/g, ({ length }, d) => length + d);
console.log(result);

Counting Duplicate elements in an array: Javascript

Could someone please look over my code and explain why my return value = 3 when it should be 2? The object has the correct count {1: 2, 2: 3, 3: 1, 4: 1, 5: 1}. Only two values are >= 2.
function countDuplicates(arr) {
let dupNums = {};
let count = 0;
​
for (let i=0; i<arr.length; i++) {
​
if (dupNums[arr[i]] === undefined) {
dupNums[arr[i]] = 0;
}
​
if (dupNums[arr[i]] !== undefined) {
dupNums[arr[i]] += 1;
}
​
if (dupNums[arr[i]] >= 2) {
count++;
}
}
return count;
}
console.log(countDuplicates([1,2,1,3,2,4,5,2]));
You have three 2s and two 1s. Each time a duplicate is found, count gets incremented.
Iterate over the values of the object afterwards instead, and count up the number of values which are >= 2:
function countDuplicates(arr) {
const dupNums = {};
for (const num of arr) {
dupNums[num] = (dupNums[num] || 0) + 1;
};
return Object.values(dupNums)
.filter(num => num >= 2)
.length;
}
console.log(countDuplicates([1, 2, 1, 3, 2, 4, 5, 2]));
or with reduce:
function countDuplicates(arr) {
const dupNums = {};
for (const num of arr) {
dupNums[num] = (dupNums[num] || 0) + 1;
};
return Object.values(dupNums)
.reduce((a, num) => a + (num >= 2), 0)
}
console.log(countDuplicates([1, 2, 1, 3, 2, 4, 5, 2]));
Use one Set to track dup nums and another Set for tracking count.
Following should work for you scenario.
function countDuplicates(arr) {
const dupNums = new Set();
const countSet = new Set();
arr.forEach((num) =>
dupNums.has(num) ? countSet.add(num) : dupNums.add(num)
);
return countSet.size;
}
console.log(countDuplicates([1, 2, 1, 3, 2, 4, 5, 2]));

Find duplicate pairs in an array

I have an array a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7]
I want to fetch all the duplicate pair in this array list.
Since there are pairs of 2 and 7 the output should be -
Output: [2, 7]
I tried writing my own logic but I am very weak in that area. Can somebody help?
function getDuplicateArrayElements(arr){
let sorted_arr = arr.slice().sort();
let results = [];
for (let i = 0; i < sorted_arr.length; i++) {
let matchingElementCount = 1;
for (let j = i + 1; j < sorted_arr.length - i; j++) {
if (sorted_arr[j] === sorted_arr[i]) {
++matchingElementCount;
} else {
if(matchingElementCount % 2 === 0) {
results.push(sorted_arr[i]);
}
i = j - 1;
break;
}
}
}
return results; } var a = [1,1,1,2,2,3,3,3,4,6,6,6,7,7]; var duplicateValues= getDuplicateArrayElements(a);
You can achieve your result by using reduce and forEach.
const arr = [1,1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
// Generate a hashmap from the given array for counting the frequency.
const hashMap = arr.reduce((a, c) => {
a[c] = (a[c] || 0) + 1;
return a;
}, {});
const pair = [];
// If the frequency is divided by 2 then push the key of the hashMap into pair array.
Object.entries(hashMap).forEach(([k, v]) => {
if (v % 2 === 0) {
[...Array(Math.floor(v / 2))].forEach(_ => pair.push(k));
}
})
console.log(pair);
You can grab the frequency of each number, and then filter out any which have an odd frequency. You can then .flatMap() the frequencies to an array containing your number for each pair you found like so:
const a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
const freq = a.reduce((m, n) => m.set(n, (m.get(n) || 0) + 1), new Map);
const res = [...freq].filter(([n, count]) => count % 2 == 0).flatMap(([n, c]) => Array(c/2).fill(n));
console.log(res);
This way, if you have four 1s (ie: two pairs of 1s), the filter will pick up on that, allowing you to flat-map the [1, 4] array to an array of [1, 1], which is merged into the larger resulting array.
You could create a helper map and keep the counts of each number as the values and the numbers itself as the keys. After iterating through the array, you only need to find the ones with a count divisible by 2:
var a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 7, 7]
function findDuplicates(arr) {
const map = {};
for (const curr of arr) {
if (!map[curr]) {
map[curr] = 0;
}
map[curr]++;
}
const res = [];
for (const key in map) {
if (map.hasOwnProperty(key) && map[key] % 2 === 0) {
res.push(Number.parseInt(key));
}
}
return res;
}
console.log(findDuplicates(a));
You can first count the occurrence of each numbers and if it is greater than 0 and divisible by 2 then add these to final result else don't
function getDuplicateArrayElements(arr) {
let map = {}
let results = [];
for (let num of arr) {
map[num] = map[num] || 0
map[num]++
}
return Object.keys(map)
.filter(v => map[v] && map[v] % 2 === 0)
.map(v => new Array(map[v]/2).fill(+v))
.flat()
.sort()
}
var a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 7, 7,8,8,8,8];
var duplicateValues = getDuplicateArrayElements(a);
console.log(duplicateValues)
const a = {};
[1,1,1,2,2,3,3,3,4,6,6,6,7,7].forEach(v => {a[v] = a[v] ? a[v] + 1 : 1});
const l = [];
Object.keys(a).forEach(k => !(a[k] % 2) && l.push(k));
Here you go:
function getDuplicateArrayElements(arr){
var dupilcates=arr.filter(x => arr.filter(y=>y==x).length==2);
var found=[];
for(var i=0;i<dupilcates.length;i=i+2)
found.push(dupilcates[i]);
return found;
}
This will give you the desired pairs. with [1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 6, 7, 7] input it will return [1,1,2,6,6,7]:
function getDuplicateArrayElements(arr){
let sorted_arr = arr.slice().sort();
let results = [];
let i = 0;
while (i < sorted_arr.length) {
let counter = 1;
let j = i;
while (sorted_arr[j] === sorted_arr[j+1]) {
counter++;
j++;
}
if (counter%2 == 0) {
results.push(...Array(counter/2).fill(sorted_arr[i]))
}
i += counter;
}
return results;
}
var a = [1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 6, 7, 7];
console.log(getDuplicateArrayElements(a));
Another rather concise solution:
a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
uniques = new Set(a); //filter out duplicates
res = [];
uniques.forEach((key)=>{
if(a.filter(elem => elem === key).length === 2){res.push(key)};
//filter out only the elements which match the key being tested
//if there are 2, push to result
})
Edit: even more concise, but perhaps less efficient:
a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
res = Array.from(new Set(a.filter(elem => a.filter(el => el === elem).length === 2)));
Javascript has awesome JSON object, in my opinion, you can use json as a dictionary;
{ key: _value }.
Loop throw array one times, no sort, no slice
key is array's element value, _value is frequency
var frequencies = {};
for (let i = 0; i < a.length; a++) {
if (result[a[i]] == 'over') continue;
if (result[a[i]] == undefined) { // First times
result[a[i]] = 1
} else if (result[a[i]] == 1) { // Second times
result[a[i]] = 2
} else { // Ignore if > 2
result[a[i]] = 'over'
}
}
// result: {1: "over", 2: 2, 3: "over", 4: "over", 6: "over", 7: 2}
so now pick keys have value equal 2
function getDuplicateArrayElements(numbers: number[]): number[] {
const occurences = new Map<number, number>();
for (let number of numbers) {
if (occurences.has(number)) {
const current = occurences.get(number)!;
occurences.set(number, current + 1);
} else
occurences.set(number, 1)
}
return (
Array
.from(occurences.entries())
.reduce<number[]>(
(accumulator, [key, value]) => {
if (value === 2) {
return accumulator.concat(key)
}
return accumulator
},
[]
)
)
}
const a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 6, 6, 6, 7, 7];
getDuplicateArrayElements(a); // [2, 7]

How to find and log the longest repeating serie of numbers in array with javascript

My problem is I can't console.log the repeating after another same numbers in the array. I can find which number how many times appears with this code:
var array = [2, 1, 1, 2, 3, 3, 2, 2, 2, 1],
currentNum = 1,
counter = 0,
item;
for (var i = 0; i < array.length; i++) {
for (var j = i; j < array.length; j++) {
if (array[i] == array[j])
counter++;
if (currentNum < counter) {
currentNum = counter;
item = array[i];
}
}
counter = 0;
}
console.log(item + " ( " + currentNum + " times ) ");
But my real issue is that I want to log the 2, 2, 2 part and I don't know how.
Thank you guys very much in advance!
Following will find the first instance of longest (assuming more than one same length sequence)
The first reduce() creates subarrays for each sequence, the second reduce() checks lengths of those sub arrays returning the first instance of longest sequence
var array = [2, 1, 1, 2, 3, 3, 2, 2, 2, 1];
var res = array.reduce(function(a,c,i){
if(a.length && a[a.length-1][0] ===c){
a[a.length-1].push(c)
}else{
a.push([c]);
}
return a
},[]).reduce(function(a,c){
return c.length > a.length ? c : a;
});
console.log('Sequence length=',res.length);
console.log('Value=', res[0]);
If you expect multiple same length sequences and want to capture all the values that match can modify second reduce something like:
var array = [2, 1, 1, 2, 3, 3, 2, 2, 2, 1, 2, 2, 2, 7, 7, 7];
var res = array.reduce(function(a,c,i){
if(a.length && a[a.length-1][0] ===c){
a[a.length-1].push(c)
}else{
a.push([c]);
}
return a
},[]).reduce(function(a,c){
if(c.length > a.len){
// reset when longer sequence found
a.values = [c[0]];
a.len = c.length;
} else if(c.length === a.len){
// add new value when same length found
a.values.push(c[0]);
}
return a
},{len:0,values:[]});
console.log('Sequence length=', res.len)
console.log('How many times=', res.values.length)
console.log('Values = ', res.values.join() )
Array.prototype.forEach or reduce is better for iteration through an array.
Here is a solution with a single going through array (just 3 additional variables :) )
var array = [2, 1, 1, 2, 3, 3, 2, 2, 2, 1]
var item = array[0], maxTimes = 1, currentTimes = 1
array.reduce(function(prev, current) {
if (prev === current) {
currentTimes = currentTimes + 1
if (currentTimes > maxTimes) {
maxTimes = currentTimes
item = current
}
} else {
currentTimes = 1
}
return current
})
console.log(item, maxTimes)
You could use Array#reduce with an object which holds the temporary result and the actual count of the item.
If an item is equal to the last item, last count is incremented and checked if the count is greater than the temporary count. Then the temporary count is replaced by the actual count.
var array = [2, 1, 1, 2, 3, 3, 2, 2, 2, 1],
count = array.reduce(function (r, a, i, aa) {
if (a === aa[i - 1]) {
r.last.count++;
if (!(r.last.count <= r.result.count)) {
r.result = r.last;
}
} else {
r.last = { value: a, count: 1 };
}
return r;
}, { last: {}, result: {} }).result;
console.log(count);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories