Counting common elements of two Arrays in JavaScript (reduce function) - javascript

I met an unexpected result when I count the number of common elements in two arrays. When I use reduce function, it doesn't work. But filter version returns correct result. I want to know what's wrong with my reduce version.
var ls = [1, 2, 3, 4, 5];
var ms = [4, 5, 6, 1, 2];
console.log(ls.reduce((acc, e) => (ms.includes(e) ? 1 + acc : 0), 0));
// 2, incorrect
console.log(ls.filter(e => ms.includes(e)).length);
// 4, correct

Because in your reduce version, when the element is not found, you reset the acc back to zero instead of returning it as is
var ls = [1, 2, 3, 4, 5];
var ms = [4, 5, 6, 1, 2];
console.log(ls.reduce((acc, e) => (ms.includes(e) ? 1 + acc : acc), 0));
// -----------------------------------------------------------^ here
// 4, now corrected

When your callback function that's the first parameter of the reduce function hits the third item in the ls array, "3", it finds that it's not a member of the ms array. This causes the ternary operator to return the right hand expression 0, which resets your accumulator variable, acc. This will restart the count at 0.
Instead, you should return the current value of the accumulator variable instead of 0 like this:
console.log(ls.reduce(acc,e) => (ms.includes(e) ? 1 + acc: acc), 0));
That will give you the correct count of 4 matching elements.

Related

I need to understand how the following code works. What is the step by step to get from that array to the object

const arr = [1, 3, 1, 2, 5, 2, 3, 4, 1, 2, 3, 4, 3]
const resultado = arr.reduce((prev, cur) => ((prev[cur] = prev[cur] + 1 || 1), prev), {})
//resultado = const resultado = { 1: 3, 2: 3, 3: 4, 4: 2, 5: 1,}
I am new to javascript and I need to understand how, in the following code, the array ends in an object.
Create an empty object
For each element in the array:
Assign the value of [the object's value at thee current value plus 1, but if that doesn't exist yet return it the value of 1] to the key of the current index's value
Return the object so that it's available during the next iteration, and at the end for the final index
reduce works by passing in an initial "value" to the callback which acts as the "accumulator". The accumulator will be the first argument to the callback, and the current element in the array iteration will be the second. The accumulator is passed in on each iteration.
In this simple example we're just going to add up some numbers. We pass in 0 as the initial value. This will be passed into the callback as the "accumulator" (acc). c is the current element in the iteration.
On the first iteration acc is 0. On the second iteration it is 1 (0 + 1. On the third iteration it is 3 (1 + 2) - always adding on the value of the current element, and then being passed back into the callback until there are no more elements.
const arr = [1, 2, 3, 4, 5];
const out = arr.reduce((acc, c) => {
return acc + c;
}, 0);
console.log(out);
The example in your question follows the same logic but because it's all on one line it makes it more difficult to understand, so here it is expanded:
Instead of 0 being passed in as an initial value we're passing in an empty object.
If the object has a key that matches the value of the current element add 1 to that property value, otherwise initialise that property value to 1.
Return the accumulator for the next iteration.
const arr = [1, 3, 1, 2, 5, 2, 3, 4, 1, 2, 3, 4, 3];
const resultado = arr.reduce((acc, c) => {
if (acc[c]) {
++acc[c];
} else {
acc[c] = 1;
}
return acc;
}, {});
console.log(resultado);

In a Given Array, I am trying to get the Value that are having a even number of occurences,

I am trying to get my hand dirty with Javascript
I want to solve the following exercise (found on Codewars):
Given an array of integers, find the one that appears an odd number of times.
There will always be only one integer that appears an odd number of
times.
[7] should return 7, because it occurs 1 time (which is odd). [0]
should return 0, because it occurs 1 time (which is odd). [1,1,2]
should return 2, because it occurs 1 time (which is odd). [0,1,0,1,0]
should return 0, because it occurs 3 times (which is odd).
[1,2,2,3,3,3,4,3,3,3,2,2,1] should return 4, because it appears 1 time
(which is odd).
this is my code:
function findOdd(A) {
const isOdd = (x) => {
return x%2;
}
const counts ={};
for ( i of A)
{
counts[i]= counts[i] ? counts[i] +1:1;
}
const numOccurences = (Object.values(counts));
const occurences = Object.getOwnPropertyNames(counts);
let evenOccurence=0;
let oddOccurence;
for (let y=0;y<numOccurences.length;y++)
{
if(isOdd(numOccurences[y]))
{
console.log("numOccurences[y] is equal to: ",numOccurences[y])
evenOccurence = numOccurences[y];
console.log(`value ${occurences[y]} is appearing ${numOccurences} times which is even`)
}
// }
// console.log("evenOccurence",evenOccurence);
// return evenOccurence;
}
return evenOccurence;
}
// console.log(findOdd([7]));
console.log(findOdd([7,7,8,8,7,5,5,5,5,5,5,5]));
my issue is the value I am putting in evenOccurrence, I would expect an integer, but it comes as 7,3,2 in the array given as an example.
could anyone help me please?
Thanks in advance
You could take a bitwise XOR ^ which wipes out even count values.
const
odd = array => array.reduce((a, b) => a ^ b, 0);
console.log(odd([1, 2, 2, 3, 3, 3, 4, 3, 3, 3, 2, 2, 1]));
console.log(odd([7]));
console.log(odd([1, 1, 2]));
Another approach. With an object for keeping the state. The value is either true or false depending on the odd appearance of the value of the array.
Finally take all keys and find the one with the true value.
const
odd = array => {
const states = {};
for (const value of array) states[value] = !states[value];
return +Object.keys(states).find(k => states[k]);
};
console.log(odd([1, 2, 2, 3, 3, 3, 4, 3, 3, 3, 2, 2, 1]));
console.log(odd([7]));
console.log(odd([1, 1, 2]));
Updated your answer with comment.
function findOdd(A) {
const isOdd = (x) => {
return x % 2;
}
const counts = {}; // key with will be unique set of A and value will be part will be occurence count
for (i of A) {
counts[i] = counts[i] ? counts[i] + 1 : 1;
}
// const numOccurences = (Object.values(counts)); // her you are just getting list of how many time they occured, without any reference to A or their keys
// const occurences = Object.getOwnPropertyNames(counts);
let evenOccurence = []; // if you want to return a list, create a list and push values in it
for (let key of Object.keys(counts)) { // key is unique value of A
let occurenceCount = counts[key];
if (isOdd(occurenceCount)) {
console.log("numOccurences of key [", key,"] is equal to: ", occurenceCount, ' odd')
} else {
console.log("numOccurences of key [", key,"] is equal to: ", occurenceCount, ' event')
evenOccurence.push(key); }
}
return evenOccurence;
}
console.log(findOdd([7, 7, 8, 8, 7, 5, 5, 5, 5, 5, 5, 5]));
#Nina Scholz's first algorithm is a masterpiece. Basically it is very simple if you are ok with bitwise operations. I just would like to simplify the same thing down to daily math.
var odd = array => array.sort().reduce((a,b,i) => i%2 ? a-b : a+b);
console.log(odd([1, 2, 2, 3, 3, 3, 4, 3, 3, 3, 2, 2, 1]));
console.log(odd([7]));
console.log(odd([1, 1, 2]));

How do you test whether both sides of an array total the same? | Javascript Algorithm

Question
You are going to be given an array of integers. Your job is to take that array and find an index N where the sum of the integers to the left of N is equal to the sum of the integers to the right of N. If there is no index that would make this happen, return -1.
For example:
Let's say you are given the array {1,2,3,4,3,2,1}: Your function will return the index 3, because at the 3rd position of the array, the sum of left side of the index ({1,2,3}) and the sum of the right side of the index ({3,2,1}) both equal 6.
Answer
function findEvenIndex(arr){
for(let i = 0; i <arr.length; i++){
let arr1 = arr.slice(0, (arr[i] - 1));
let arr2 = arr.slice((arr[i] + 1),);
let arr11 = arr1.reduce((total, item)=>{
return total + item;
}, 0);
let arr22 = arr2.reduce((total, item)=>{
return total + item;
}, 0);
if(arr11 === arr22){
return arr[i];
}
}
return -1;
}
console.log(findEvenIndex([1, 2, 3, 4, 3, 2, 1]))
console.log(findEvenIndex([1, 100, 50, -51, 1, 1]))
console.log(findEvenIndex([1, 2, 3,4,5,6]))
I can't see an error here, but it yields incorrect results. Any ideas?
You have this part:
let arr1 = arr.slice(0, (arr[i] - 1));
let arr2 = arr.slice((arr[i] + 1),);
This is incorrect: arr[i]. That is a value, eg in [2,4,6,8,10] arr[3]==8. You want to slice on the index itself:
let arr1 = arr.slice(0, i - 1);
let arr2 = arr.slice(i + 1,);
Please note: There is another error in the two lines :) I leave that to you. Hint: you're now slicing two values out of the array instead of one. Perform the following code in your head first, then somewhere where you verify your results.
let arr = [0,1,2,3,4]
let x = 2;
console.log(arr.slice(0, x - 1));
console.log(arr.slice(x + 1,));
You could also use the array method findIndex, which, we shouldn't be surprised to learn, finds an index in an array subject to a certain condition.
const sum = (ns) =>
ns .reduce ((total, n) => total + n, 0)
const findBalancedIndex = (ns) =>
ns .findIndex ((_, i) => sum (ns.slice (0, i)) === sum (ns.slice (i + 1)))
console .log (findBalancedIndex ([1, 2, 3, 4, 3, 2, 1]))
console .log (findBalancedIndex ([1, 100, 50, -51, 1, 1]))
console .log (findBalancedIndex ([1, 2, 3, 4, 5, 6]))
Here we include a simple helper function to find the sum of an array, and then we pass a function to findIndex which uses it twice on the elements before the index and those after it. We use the second parameter of the callback function, the index to do this. This means we are skipping the first parameter altogether, and rather than naming it with something like n, we use the somewhat common convention of calling it _, signalling a placeholder we won't use. Note that you don't need to subtract one from the right-hand boundary of slice, since that boundary value is already excluded. And of course, others have pointed out that you need to slice to the index and not the array value at that index.
This finds the first correct index. You would have to use a different technique if you wanted to find all such indices. (That it's possible to have more than one should be clear from arrays like [1, 2, 3, 0, 0, 0, 0, 3, 2, 1] -- the indices for all those 0s would work.)
you return arr[i] when you need to return just i

How to map only every second value in array

I have some array of numbers:
var arr = [1, 7, 1, 4];
I want to increase only every first value, such that the expected output would be: [2, 7, 2, 4]
I tried some combination of map and filter but I don't understand how it can work together...
var mapuj = arr.map(x => x *2);
You can use map() and use second argument which is idnex to determine if it's at event index or not
let arr = [1, 7, 1, 4];
let output = arr.map((n, index) => index % 2 === 0 ? n * 2 : n);
console.log(output);

How to count certain elements in array?

I have an array:
[1, 2, 3, 5, 2, 8, 9, 2]
I would like to know how many 2s are in the array.
What is the most elegant way to do it in JavaScript without looping with for loop?
[this answer is a bit dated: read the edits, in the notion of 'equal' in javascript is ambiguous]
Say hello to your friends: map and filter and reduce and forEach and every etc.
(I only occasionally write for-loops in javascript, because of block-level scoping is missing, so you have to use a function as the body of the loop anyway if you need to capture or clone your iteration index or value. For-loops are more efficient generally, but sometimes you need a closure.)
The most readable way:
[....].filter(x => x==2).length
(We could have written .filter(function(x){return x==2}).length instead)
The following is more space-efficient (O(1) rather than O(N)), but I'm not sure how much of a benefit/penalty you might pay in terms of time (not more than a constant factor since you visit each element exactly once):
[....].reduce((total,x) => (x==2 ? total+1 : total), 0)
or as a commenter kindly pointed out:
[....].reduce((total,x) => total+(x==2), 0)
(If you need to optimize this particular piece of code, a for loop might be faster on some browsers... you can test things on jsperf.com.)
You can then be elegant and turn it into a prototype function:
[1, 2, 3, 5, 2, 8, 9, 2].count(2)
Like this:
Object.defineProperties(Array.prototype, {
count: {
value: function(value) {
return this.filter(x => x==value).length;
}
}
});
You can also stick the regular old for-loop technique (see other answers) inside the above property definition (again, that would likely be much faster).
2017 edit:
Whoops, this answer has gotten more popular than the correct answer. Actually, just use the accepted answer. While this answer may be cute, the js compilers probably don't (or can't due to spec) optimize such cases. So you should really write a simple for loop:
Object.defineProperties(Array.prototype, {
count: {
value: function(query) {
/*
Counts number of occurrences of query in array, an integer >= 0
Uses the javascript == notion of equality.
*/
var count = 0;
for(let i=0; i<this.length; i++)
if (this[i]==query)
count++;
return count;
}
}
});
You could define a version .countStrictEq(...) which used the === notion of equality. The notion of equality may be important to what you're doing! (for example [1,10,3,'10'].count(10)==2, because numbers like '4'==4 in javascript... hence calling it .countEq or .countNonstrict stresses it uses the == operator.)
Caveat:
Defining a common name on the prototype should be done with care. It is fine if you control your code, but bad if everyone wants to declare their own [].count function, especially if they behave differently. You may ask yourself "but .count(query) surely sounds quite perfect and canonical"... but consider perhaps you could do something like [].count(x=> someExpr of x). In that case you define functions like countIn(query, container) (under myModuleName.countIn), or something, or [].myModuleName_count().
Also consider using your own multiset data structure (e.g. like python's 'collections.Counter') to avoid having to do the counting in the first place. This works for exact matches of the form [].filter(x=> x==???).length (worst case O(N) down to O(1)), and modified will speed up queries of the form [].filter(filterFunction).length (roughly by a factor of #total/#duplicates).
class Multiset extends Map {
constructor(...args) {
super(...args);
}
add(elem) {
if (!this.has(elem))
this.set(elem, 1);
else
this.set(elem, this.get(elem)+1);
}
remove(elem) {
var count = this.has(elem) ? this.get(elem) : 0;
if (count>1) {
this.set(elem, count-1);
} else if (count==1) {
this.delete(elem);
} else if (count==0)
throw `tried to remove element ${elem} of type ${typeof elem} from Multiset, but does not exist in Multiset (count is 0 and cannot go negative)`;
// alternatively do nothing {}
}
}
Demo:
> counts = new Multiset([['a',1],['b',3]])
Map(2) {"a" => 1, "b" => 3}
> counts.add('c')
> counts
Map(3) {"a" => 1, "b" => 3, "c" => 1}
> counts.remove('a')
> counts
Map(2) {"b" => 3, "c" => 1}
> counts.remove('a')
Uncaught tried to remove element a of type string from Multiset, but does not exist in Multiset (count is 0 and cannot go negative)
sidenote: Though, if you still wanted the functional-programming way (or a throwaway one-liner without overriding Array.prototype), you could write it more tersely nowadays as [...].filter(x => x==2).length. If you care about performance, note that while this is asymptotically the same performance as the for-loop (O(N) time), it may require O(N) extra memory (instead of O(1) memory) because it will almost certainly generate an intermediate array and then count the elements of that intermediate array.
Modern JavaScript:
Note that you should always use triple equals === when doing comparison in JavaScript (JS). The triple equals make sure, that JS comparison behaves like double equals == in other languages (there is one exception, see below). The following solution shows how to solve this the functional way, which will ensure that you will never have out of bounds error:
// Let has local scope
let array = [1, 2, 3, 5, 2, 8, 9, 2]
// Functional filter with an Arrow function
// Filter all elements equal to 2 and return the length (count)
array.filter(x => x === 2).length // -> 3
The following anonymous Arrow function (lambda function) in JavaScript:
(x) => {
const k = 2
return k * x
}
may be simplified to this concise form for a single input:
x => 2 * x
where the return is implied.
Always use triple equals: === for comparison in JS, with the exception of when checking for nullability: if (something == null) {} as it includes a check for undefined, if you only use double equals as in this case.
Very simple:
var count = 0;
for(var i = 0; i < array.length; ++i){
if(array[i] == 2)
count++;
}
2017:
If someone is still interested in the question, my solution is the following:
const arrayToCount = [1, 2, 3, 5, 2, 8, 9, 2];
const result = arrayToCount.filter(i => i === 2).length;
console.log('number of the found elements: ' + result);
Here is an ES2017+ way to get the counts for all array items in O(N):
const arr = [1, 2, 3, 5, 2, 8, 9, 2];
const counts = {};
arr.forEach((el) => {
counts[el] = counts[el] ? (counts[el] + 1) : 1;
});
You can also optionally sort the output:
const countsSorted = Object.entries(counts).sort(([_, a], [__, b]) => a - b);
console.log(countsSorted) for your example array:
[
[ '2', 3 ],
[ '1', 1 ],
[ '3', 1 ],
[ '5', 1 ],
[ '8', 1 ],
[ '9', 1 ]
]
If you are using lodash or underscore the _.countBy method will provide an object of aggregate totals keyed by each value in the array. You can turn this into a one-liner if you only need to count one value:
_.countBy(['foo', 'foo', 'bar'])['foo']; // 2
This also works fine on arrays of numbers. The one-liner for your example would be:
_.countBy([1, 2, 3, 5, 2, 8, 9, 2])[2]; // 3
Weirdest way I can think of doing this is:
(a.length-(' '+a.join(' ')+' ').split(' '+n+' ').join(' ').match(/ /g).length)+1
Where:
a is the array
n is the number to count in the array
My suggestion, use a while or for loop ;-)
Not using a loop usually means handing the process over to some method that does use a loop.
Here is a way our loop hating coder can satisfy his loathing, at a price:
var a=[1, 2, 3, 5, 2, 8, 9, 2];
alert(String(a).replace(/[^2]+/g,'').length);
/* returned value: (Number)
3
*/
You can also repeatedly call indexOf, if it is available as an array method, and move the search pointer each time.
This does not create a new array, and the loop is faster than a forEach or filter.
It could make a difference if you have a million members to look at.
function countItems(arr, what){
var count= 0, i;
while((i= arr.indexOf(what, i))!= -1){
++count;
++i;
}
return count
}
countItems(a,2)
/* returned value: (Number)
3
*/
I'm a begin fan of js array's reduce function.
const myArray =[1, 2, 3, 5, 2, 8, 9, 2];
const count = myArray.reduce((count, num) => num === 2 ? count + 1 : count, 0)
In fact if you really want to get fancy you can create a count function on the Array prototype. Then you can reuse it.
Array.prototype.count = function(filterMethod) {
return this.reduce((count, item) => filterMethod(item)? count + 1 : count, 0);
}
Then do
const myArray =[1, 2, 3, 5, 2, 8, 9, 2]
const count = myArray.count(x => x==2)
Most of the posted solutions using array functions such as filter are incomplete because they aren't parameterized.
Here goes a solution with which the element to count can be set at run time.
function elementsCount(elementToFind, total, number){
return total += number==elementToFind;
}
var ar = [1, 2, 3, 5, 2, 8, 9, 2];
var elementToFind=2;
var result = ar.reduce(elementsCount.bind(this, elementToFind), 0);
The advantage of this approach is that could easily change the function to count for instance the number of elements greater than X.
You may also declare the reduce function inline
var ar = [1, 2, 3, 5, 2, 8, 9, 2];
var elementToFind=2;
var result = ar.reduce(function (elementToFind, total, number){
return total += number==elementToFind;
}.bind(this, elementToFind), 0);
Really, why would you need map or filter for this?
reduce was "born" for these kind of operations:
[1, 2, 3, 5, 2, 8, 9, 2].reduce( (count,2)=>count+(item==val), 0);
that's it! (if item==val in each iteration, then 1 will be added to the accumulator count, as true will resolve to 1).
As a function:
function countInArray(arr, val) {
return arr.reduce((count,item)=>count+(item==val),0)
}
Or, go ahead and extend your arrays:
Array.prototype.count = function(val) {
return this.reduce((count,item)=>count+(item==val),0)
}
It is better to wrap it into function:
let countNumber = (array,specificNumber) => {
return array.filter(n => n == specificNumber).length
}
countNumber([1,2,3,4,5],3) // returns 1
I use this:
function countElement(array, element) {
let tot = 0;
for(var el of array) {
if(el == element) {
tot++;
}
}
return tot;
}
var arr = ["a", "b", "a", "c", "d", "a", "e", "f", "a"];
console.log(countElement(arr, "a")); // 4
var arrayCount = [1,2,3,2,5,6,2,8];
var co = 0;
function findElement(){
arrayCount.find(function(value, index) {
if(value == 2)
co++;
});
console.log( 'found' + ' ' + co + ' element with value 2');
}
I would do something like that:
var arrayCount = [1,2,3,4,5,6,7,8];
function countarr(){
var dd = 0;
arrayCount.forEach( function(s){
dd++;
});
console.log(dd);
}
I believe what you are looking for is functional approach
const arr = ['a', 'a', 'b', 'g', 'a', 'e'];
const count = arr.filter(elem => elem === 'a').length;
console.log(count); // Prints 3
elem === 'a' is the condition, replace it with your own.
Array.prototype.count = function (v) {
var c = 0;
for (let i = 0; i < this.length; i++) {
if(this[i] === v){
c++;
}
}
return c;
}
var arr = [1, 2, 3, 5, 2, 8, 9, 2];
console.log(arr.count(2)); //3
Solution by recursion
function count(arr, value) {
if (arr.length === 1) {
return arr[0] === value ? 1 : 0;
} else {
return (arr.shift() === value ? 1 : 0) + count(arr, value);
}
}
count([1,2,2,3,4,5,2], 2); // 3
Create a new method for Array class in core level file and use it all over your project.
// say in app.js
Array.prototype.occurrence = function(val) {
return this.filter(e => e === val).length;
}
Use this anywhere in your project -
[1, 2, 4, 5, 2, 7, 2, 9].occurrence(2);
// above line returns 3
Here is a one liner in javascript.
Use map. Find the matching values (v === 2) in the array, returning an array of ones and zeros.
Use Reduce. Add all the values of the array for the total number found.
[1, 2, 3, 5, 2, 8, 9, 2]
.map(function(v) {
return v === 2 ? 1 : 0;
})
.reduce((a, b) => a + b, 0);
The result is 3.
Depending on how you want to run it:
const reduced = (array, val) => { // self explanatory
return array.filter((element) => element === val).length;
}
console.log(reduced([1, 2, 3, 5, 2, 8, 9, 2], 2));
// 3
const reducer = (array) => { // array to set > set.forEach > map.set
const count = new Map();
const values = new Set(array);
values.forEach((element)=> {
count.set(element, array.filter((arrayElement) => arrayElement === element).length);
});
return count;
}
console.log(reducer([1, 2, 3, 5, 2, 8, 9, 2]));
// Map(6) {1 => 1, 2 => 3, 3 => 1, 5 => 1, 8 => 1, …}
You can use built-in function Array.filter()
array.filter(x => x === element).length;
var arr = [1, 2, 3, 5, 2, 8, 9, 2];
// Count how many 2 there are in arr
var count = arr.filter(x => x === 2).length;
console.log(count);
One-liner function
const countBy = (a,f)=>a.reduce((p,v,i,x)=>p+!!f(v,i,x), 0)
countBy([1,2,3,4,5], v=>v%2===0) // 2
There are many ways to find out. I think the easiest way is to use the array filter method which is introduced in es6.
function itemCount(array, item) {
return array.filter(element => element === item).length
}
const myArray = [1,3,5,7,1,2,3,4,5,1,9,0,1]
const items = itemCount(myArray, 1)
console.log(items)
Something a little more generic and modern (in 2022):
import {pipe, count} from 'iter-ops';
const arr = [1, 2, 3, 5, 2, 8, 9, 2];
const n = pipe(arr, count(a => a === 2)).first; //=> 3
What's good about this:
It counts without creating a new array, so it is memory-efficient
It works the same for any Iterable and AsyncIterable
Another approach using RegExp
const list = [1, 2, 3, 5, 2, 8, 9, 2]
const d = 2;
const counter = (`${list.join()},`.match(new RegExp(`${d}\\,`, 'g')) || []).length
console.log(counter)
The Steps follows as below
Join the string using a comma Remember to append ',' after joining so as not to have incorrect values when value to be matched is at the end of the array
Match the number of occurrence of a combination between the digit and comma
Get length of matched items
I believe you can use the new Set array method of JavaScript to have unique values.
Example:
var arr = [1, 2, 3, 5, 2, 8, 9, 2]
var set = new Set(arr);
console.log(set);
// 1,2,3,5,8,9 . We get unique values as output.
You can use length property in JavaScript array:
var myarray = [];
var count = myarray.length;//return 0
myarray = [1,2];
count = myarray.length;//return 2

Categories

Resources