Fastest way to get count of unique elements in javascript array - javascript

I need to find the number of unique elements in an array.
var myArray = [ 10, 10, 20, 20, 30, 30, 40, 40, 40, 40, 50, 50, 50, 50, 60 ];
I want count = 6 (number of unique elements in array)
And, is there a way to do this without iterating through the array? (I assume that would be the fastest way?).
ANSWER: I used the .filter method as shown below. My actual array element is much more complex. I ended up iterating through my array and created a new array. Each element in the new array was a .substr of the old element. Then, the .filter method below worked great. THANKS to everyone!!

You need to keep a set of known values, and an auxilliary count. You can use .reduce():
var count = myArray.reduce(function(values, v) {
if (!values.set[v]) {
values.set[v] = 1;
values.count++;
}
return values;
}, { set: {}, count: 0 }).count;
Starting with an empty set of values and a count of zero, this looks at each element to see whether it's been added to the set. If it hasn't, it's added, and the count is incremented.

ES6 offers a single line solution:
new Set(myArray).size

How about filter and length:
var len = myArray.filter(function(val, i, arr) {
return arr.indexOf(val) === i;
}).length;

If you happen to be using lodash:
_.uniq(myArray).length

You can now convert your array into a unique Array and compare lengths.
Do this by changing it into Set and then back to an Array. If the Set is smaller then duplicates were removed and your original Array did not contain unique values.
const isUnique = (myArray.length === [...new Set(myArray)].length);
test:
const myArray=[1,2,2,3,4];
console.log(myArray.length === [...new Set(myArray)].length);
false
const myArray=[1,2,3,4];
console.log(myArray.length === [...new Set(myArray)].length);
true

Related

JS: Array print the values that repeat

I need to print the duplicates from an array.
For example, given the following array and index, the function will print 6,23,33,100.
var array = [3,6,67,6,23,11,100,8,93,0,17,24,7,1,33,45,28,33,23,12,99,100];
Apparently we need to do it using two 'while loops'.
Im looking for a solution, but more importantly an explanation.
Links are very much appreciated.
Thanks!
The most elegant and efficient solution is to use a while loop which iterates the array only once, so, we have O(N) complexity.
For this, we need to declare an hash which keeps the number of occurencies for each array's item. If we found a duplicate one then we store it in duplicates array.
var arr = [3,6,67,6,23,11,100,8,93,0,17,24,7,1,33,45,28,33,23,12,99,100], i = 0, hash = {}, duplicates = [];
while(i < arr.length){
hash[arr[i]] = hash[arr[i]] ? hash[arr[i]] += 1 : 1;
if (hash[arr[i]] === 2)
duplicates.push(arr[i])
i++;
}
console.log(duplicates)
You could use the filter() and indexOf() methods.
var array = [3,6,67,6,23,11,100,8,93,0,17,24,7,1,33,45,28,33,23,12,99,100];
console.log(array.filter((a,b,c) => c.indexOf(a) !== b));
a -> is the value being passed in the arrow function.
b -> is the index being passed in.
c -> is the whole array being passed in.
This line is filtering the array based on, if the original array has a value (argument a) whose index does not match the given index passed in through the arrow function (argument b).
A good sample and explanation can be found here... W3Resource
Futhermore to assist in understanding the two major components of the code the Object...
Working with objects - Javascipt
and Arrays...Javascipt Arrays
For the shortest approach, you could take a closure
(s => )( )
with a Set
(s => )(new Set)
and a check. If a value is already seen, then take this value
(s => v => s.has(v) )(new Set)
or add the value to the set and return false, because a not seen value should not in the result set.
(s => v => !s.add(v))(new Set)
var array = [3, 6, 67, 6, 23, 11, 100, 8, 93, 0, 17, 24, 7, 1, 33, 45, 28, 33, 23, 12, 99, 100],
duplicates = array.filter((s => v => s.has(v) || !s.add(v))(new Set));
console.log(duplicates);

JS Array.sort. How to remove matching value from array

I am performing an Array.sort with the compare method like so:
orderNotes(notes){
function compare(a, b) {
const noteA =a.updatedAt
const noteB =b.updatedAt
let comparison = 0;
if (noteA < noteB) {
comparison = 1;
} else if (noteA > noteB) {
comparison = -1;
}
return comparison;
}
return notes.sort(compare)
}
Now since I need to sort the array anyway and loop through each element with the Array.sort, I want to use this chance to check if the note.id matches on the neighboring note, and remove the duplicate from the array (doesn't matter which one). This will save me the trouble to loop again just to check duplication.
Is it possible to alter the array inside the compare() function and remove the duplicate?
Best
Is it possible to alter the array inside the compare() function and remove the duplicate?
You could .splice(...) the element out of it if it doesn't match, but actually this:
This will save me the trouble to loop again just to check duplication.
Is a missconception. Looping an array and doing two tasks will only be slightly faster than two loops, as only the looping part gets duplicated, not the tasks done in the loop. Therefore just:
const ids = new Set;
const result = array
.filter(it => ids.has(it.id) && ids.add(it.id))
.sort((a, b) => a.updatedAt - b.updatedAt);
It might be a simpler solution to use Array.prototype.reduce to remove the duplicates in an additional step instead of while sorting:
//Starting with your ordered array
var ordered = [1, 1, 2, 3, 3, 3, 4, 5, 6, 7, 7, 8, 9, 9, 9];
//Now create a new array excluding the duplicates
var orderedAndUnique = ordered.reduce((accum, el) => {
if (accum.indexOf(el) == -1) {
accum.push(el);
return accum;
}
return accum;
}, []);
console.log(orderedAndUnique);

This line of code finds the max element in an array, could someone please walk me through how this code accomplishes this using reduce? [duplicate]

Often I study some JavaScript interview questions, suddenly I saw a question about usage of reduce function for sorting an Array, I read about it in MDN and the usage of it in some medium articles, But sorting an Array is so Innovative:
const arr = [91,4,6,24,8,7,59,3,13,0,11,98,54,23,52,87,4];
I thought a lot, but I've no idea about how answer this question, how must be the reduce call back function? what is the initialValue of reduce function? And what are the accumulator and currentValue of call back function of reduce?
And at the end, does this way have some benefits than other sorting algorithms? Or Is it useful to improve other algorithms?
It makes no sense to use reduce here, however you could use a new array as an accumulator and do insertion sort with all elements:
array.reduce((sorted, el) => {
let index = 0;
while(index < sorted.length && el < sorted[index]) index++;
sorted.splice(index, 0, el);
return sorted;
}, []);
Here is the version without reduce:
array.sort((a, b) => a - b);
Now some general tips for writing reducers:
how must be the reduce call back function?
You either take an approach with an accumulator, then the reducer should apply a modification to the accumulator based on the current element and return it:
(acc, el) => acc
Or if accumulator and the elements have the sane type and are logically equal, you dont need to distinguish them:
(a, b) => a + b
what is the initialValue of reduce function?
You should ask yourself "What should reduce return when it is applied on an empty array?"
Now the most important: When to use reduce? (IMO)
If you want to boil down the values of an array into one single value or object.
Array.sort mutates the array where using Array.reduce encourages a pure function. You could clone the array before sorting.
I believe this question is designed to get you thinking differently by enforcing constraints. It tests your knowledge of how reduce works and as the answers show there are many ways to skin a cat. It'll show your personal flavour of js in solving this.
I chose to use Array.findIndex and Array.splice.
const sortingReducer = (accumulator, value) => {
const nextIndex = accumulator.findIndex(i => value < i );
const index = nextIndex > -1 ? nextIndex : accumulator.length;
accumulator.splice(index, 0, value);
return accumulator;
}
const input = [5,4,9,1];
const output = input.reduce(sortingReducer, []);
Testing with the sample input produces
arr.reduce(sortingReducer, [])
// (17) [0, 3, 4, 4, 6, 7, 8, 11, 13, 23, 24, 52, 54, 59, 87, 91, 98]
Here is an example of the sorting an array in descending order using reduce function.
what is the initialValue of reduce function
In this below function the initial value is the [] which is passed as thisArg in the reduce function.
array.reduce(function(acc,curr,currIndex,array){
//rest of the code here
},[]//this is initial value also known as thisArg)
So basically an empty array is passed and the elements will be be pushed to this array
The accumulator here is the empty array.
const arr = [91, 4, 6, 24, 8, 7, 59, 3, 13, 0, 11, 98, 54, 23, 52, 87, 4];
var m = arr.reduce(function(acc, cur) {
// this arrVar will have the initial array
let arrVar = arr;
// get the max element from the array using Math.max
// ... is spread operator
var getMaxElem = Math.max(...arrVar);
// in the accumulator we are pushing the max value
acc.push(getMaxElem);
// now need to remove the max value from the array, so that next time it
// shouldn't not be considered
// splice will return a new array
// now the arrVar is a new array and it does not contain the current
// max value
arrVar = arrVar.splice(arrVar.indexOf(getMaxElem), 1, '')
return acc;
}, []);
console.log(m)
Here's an (imo) more elegant version of Jonas W's insertion sort solution. The callback just builds a new array of all lower values, the new one and all higher values. Avoids using explicit loops or indices, so it's easier to see at a glance that it works correctly.
const insertValue = (arr, value) =>
[...arr.filter(n => n <= value), value, ...arr.filter(n => n > value)]
const testArr = [91, 4, 6, 24, 8, 7, 59, 3, 13, 0, 11, 98, 54, 23, 52, 87, 4]
console.log(testArr.reduce(insertValue, []))
reduce constraints yourself to online sorting algorithms, where each element in the array is seen once and you do not now in advance the length of your array (note that using closures you could give more information to the reducing function but this kinds of defeats the purpose of the question).
insertion sort is an obvious and easy example; I won't detail the implementation as the other answers are already very good in this regard. However you can mention a few optimizations that might probably seen as very positive to the interviewer:
Use binary search to find the insertion point can reduce the complexity of an insertion step from O(n) to O(log n). This is called binary insertion sort: the overall number of comparisons will go from O(n^2) to O(n log n). This won't be faster because the real cost is due to "splicing" the output array but if you had expensive comparisons (say, sorting long strings for instance) it could make a difference.
If you sort integer, you can use radix sort and implement a linear online sorting algorithm with reduce. This is quite trickier to implement, but very suited to a reduction.
You could use some functions for getting an array if not an array is supplied, a function which returns a sorted array by taking two parameters and a sort callback which includes the above by using another reduce method for getting a part result of a sorted array.
const
getArray = a => Array.isArray(a) ? a : [a],
order = (a, b) => a < b ? [a, b] : [b, a],
sort = (a, b) => getArray(a).reduce((r, v) => r.concat(order(r.pop(), v)), [b]),
array = [91, 4, 6, 24, 8, 7, 59, 3, 13, 0, 11, 98, 54, 23, 52, 87, 4];
console.log(array.reduce(sort));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use an insertion sort:
let array = [91, 4, 6, 24, 8, 7, 59, 3, 13, 0, 11, 98, 54, 23, 52, 87, 4];
let countIfLess = (array,v)=> array.reduce((c,n)=>n<v?c+1:c,0);
let countIfEqual = (array,v)=> array.reduce((c,n)=>n==v?c+1:c,0);
console.log(
array.reduce(
(a,v,i,array)=>( a[countIfLess(array,v) + countIfEqual(a,v)]=v, a ),
new Array(array.length)
)
);
This will create the destination array once and then perform insertions into it at each step of the reduce without having to recreate the destination array.
There are more efficient ways of implementing countIfEqual but I chose to implement all the functions using reduce rather than other array functions.
A terrible sorting algorithm can be written in a one liner with ES6:
const sorter = (xs, x) => xs.slice(-1)[0] >= x ? [x, ...xs] : [...xs, x];
If the present element is larger or equal the last element of the previously sorted list it is appended to the end, otherwise to the beginning.
[3,4,1].reduce(sorter,[]).reduce(sorter,[])
//returns [1,3,4]
It takes several applications to its return to sort anything but the most simple arrays.
But it will eventually get there. That calls for a recursion!
const arr = [91,4,6,24,8,7,59,3,13,0,11,98,54,23,52,87,4];
const sorter2 =(as) => as.reduce(
(xs, x) => x >= xs.slice(-1)[0] ? [...xs, x]
: xs[0] < x ? sorter2([x, ...xs])
: [x, ...xs],
[],
);
const result = sorter2(arr);
console.log(result.join(', '));
When the present value is larger than the last value of already processed array it is appended. If it is smaller than the first element it is prepended. Only if it is neither before or after the the present value and the accumulated array are sorted again by a recursive call. The method should be equivalent to an insertion sort (please comment!).
Though, reduce is not ideally meant for the sorting. The following solution is just like a forEach or any loop function trying to be achieved with Array.reduce function.
var arr = [91,4,6,24,8,7,59,3,13,0,11,98,54,23,52,87,4];
arr = arr.reduce(function(acc,val){
if(acc.length) {
var temp = [];
while(acc[acc.length -1] > val) {
temp.push(acc.pop());
}
acc.push(val);
while(temp.length) {
acc.push(temp.pop());
}
} else {
acc.push(val);
}
return acc;
}, []);
console.log(arr);
Please note, you can use the native function Array.sort for sorting and can also have your own custom sort function where you can define your own sorting algorithm.

Filtering an array and converting it to a 2D array

I saw this interesting post yesterday, and thought it'd be important to know how to create a 2D array from sorting the given argument:
How to get even numbers array to print first instead of odds?
Below is the code snippet from Ori Drori.
I was curious to know what line of code, and which expression sorts the data and creates 2D array. I assume it's something to do with [numbersArray[i] % 2], but isn't the remainder operator returns the remainder left over?
Also it's a bit confusing as it just set one bracket for an array and use push() to make 2 different arrays.
Any reference that'd help me to understand this will also be much appreciated- thanks!
var numbersArray = [1,2,34,54,55,34,32,11,19,17,54,66,13];
function divider(numbersArray) {
var evensOdds = [[], []];
for (var i = 0; i < numbersArray.length; i++) {
evensOdds[numbersArray[i] % 2].push(numbersArray[i]);
}
return evensOdds;
}
console.log(divider(numbersArray));
evensOdds has 2 array elements. evensOdds[0] represents first array, which will hold even nums. evensOdds[1] is second element and will hold odd numbers.
When you % 2 an even number, it will result in 0 and 1 for odd number. So when iterating through the array, you % 2, which will return 0 or 1 which enables you to access the first or second array in your evensOdds array and insert it.
The resulting arrays are not sorted but does represent the split between even and odd numbers. To have a sorted results, you will need the following:
var numbersArray = [1,2,34,54,55,34,32,11,19,17,54,66,13];
function divider(numbersArray) {
var evensOdds = [[], []];
for (var i = 0; i < numbersArray.length; i++) {
evensOdds[numbersArray[i] % 2].push(numbersArray[i]);
}
return evensOdds.map(array=> array.sort((a,b)=>a-b));
}
console.log(divider(numbersArray));
In the shared code the evensOdds[numbersArray[i] % 2] line is the part that filter the numbers and inserts them in the respective array, using the indexes 0 and 1 returned from the numbersArray[i] % 2 expression:
If it returns 0 so it's an even number and it will be pushed in the first array otherwise if it returns 1 it's an odd number and will be pushed in the second array.
Another alternative:
Well you can simply use Array.filter() method to filter both evens and odds arrays:
Demo:
var numbersArray = [1, 2, 34, 54, 55, 34, 32, 11, 19, 17, 54, 66, 13];
var evens = numbersArray.filter(function(el) {
return el % 2 == 0;
});
var odds = numbersArray.filter(function(el) {
return el % 2 == 1;
});
console.log(evens);
console.log(odds);

How to reduce a javascript array into half?

I have an array containing 365 objects (date and value), and I would like to reduce this into half to make plotting faster. The reduction has to occur such that I get every other point in the array. So if the first element is for Jan 1, the second element would be for Jan 3 instead of Jan 2. I can iterate through the array and if the number is odd I can add that to the new array or vice versa. But is there a better/faster way to achieve this? I heard crossfilter.js is made for things like this, but wasn't able to figure out how to use it for this case. Any suggestions?
reduce or filter will work for this.
array.reduce(function(memo, item, index) {
index % 2 && memo.push(item);
return memo;
}, [])
array.filter(function(item, index) { return index % 2; })
What you are looking for is Array.filter. filter can be used to filter out the required values from an array, it will result in an array with length lesser or equal to the original array.
The below code returns all the odd elements in the array:
var array = [1,2,3,4,5,6,7,8,9,10]
array.filter(
function (d,indx) {
return indx%2 != 1
}
)
You can use filter function of array
var numbers = [1, 2, 3, 4, 5];
var odds = numbers.filter(function(index, item) {
return index % 2 == 1;
});

Categories

Resources