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);
Related
This is my first time writing here, so apologies in advance.
I am pretty sure I have a good grasp on the reduce() method, but I can't seem to wrap my head around one concept in particular. In this particular problem, we are asked to find elements that all of the array arguments share. I was able to construct an answer with the reduce method. I know that it works, and I know there are more efficient solutions, but I can't seem to understand how the accumulator value revises itself even though I have not reassigned its value.
Let me explain: after the first iteration of the current values which is the second array, I check to see if the current elements share commonalities with my accumulator(the first array). After checking and pushing the common values into results, results = [5, 15, 7]. The accumulator value at the beginning of the next iteration also becomes my set of results values, but again, I do not explicitly reassign the accumulator value, for example with acc = results . How does accumulator "understand" to change without explicit changes? I've kinda just accepted this mechanism as is, but would love an explanation. Please let me know if I should offer more clarification. Thank you!
function intersection(arrays) {
return arrays.reduce((acc, curr) => {
// here, acc = the first array --> 5, 15, 7 --> 15, 5
let results = []
for(let element of curr) {
if(acc.includes(element)) results.push(element)
}
// here, results = 5, 15, 7 --> 15, 5 --> 15, 5
return results
})
}
const arr1 = [5, 10, 15, 20, 7, 3];
const arr2 = [15, 88, 1, 5, 7, 21];
const arr3 = [1, 10, 15, 5, 20, 21];
console.log(intersection([arr1, arr2, arr3]));
// should log: [5, 15]
You will probably understand it better seeing this rudimentary version of reduce that simply sums the array values when called
Array.prototype.myReduce = function(callback, start) {
// inital value of acc is start value `0` set in call
let acc = start;
this.forEach((elem, i) => {
// acc gets assigned the return value from the callback
// every iteration of this internal loop
acc = callback(acc, elem, i, this)
});
// then finally gets returned from the outer function
return acc
};
const arr = [1, 2, 3]
const res = arr.myReduce((a, c, i, arr) => {
return a + c // returned to `acc` in the forEach loop above
}, 0)
console.log('Result:', res) // expect 1+2+3 = 6
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.
I have the following simple array:
my_array = [1, 11, 44, 4]
I want to produce a new array consisting of the difference between these elements, so it would be:
diff_array = [10, 33, 40]
What's the best way of going about this?
You could use Array#reduce for iterating and take the absolute delta for pushing to the result array.
Basically you need array.length - 1 deltas and iteration. In this case 3. Reduce takes, if no start value is given, the first two elements and iterates the wanted length. And while it needs the last value for the delta, the last value is returned.
At the end, the returned value of reduce is discarded, becuase it is not used anymore.
1 11 44 4 values
\ / \ / \ /
10 33 40 Math.abs(delta)
var array = [1, 11, 44, 4],
result = [];
array.reduce(function (a, b) {
result.push(Math.abs(a - b));
return b;
});
console.log(result);
here is a simple solution with a plain old for loop
array = [1, 11, 44, 4]
diff = []
for(var i = 1 ; i < array.length ; i++){
diff.push(Math.abs(array[i] - array[i-1]))
}
basically you loop starting at the second element of the array ,, and subtract from from the prev and pushing to the new array .
use this function, pass it the input array, returns the required array.
function diff(array){
var out = []
for (var i = 0; i < array.length-1; i++) {
out.push(Math.abs(array[i+1]-array[i]))
}
return out;
}
Normally one can do this with .reduce() but just for fun lets get some functional.
var myArray = [1, 11, 44, 4],
diff = a => a.length > 1 ? [Math.abs(a[1]-a[0])].concat(diff(a.slice(1))) : [];
console.log(diff(myArray));
Note: The above code is just for demonstration purposes. In your daily JS life you shouldn't do things like this. Use a whatever loop you like but never use recursion in your JS code. You want to see what i mean? Feed this array.
var myArray = Array(1000000).fill().map(_ => ~~(Math.random()*100+1));
It will beautifully crash your browser's tab. Peah..!
First I apologize if it's a duplicate (I searched but did not find this simple example...), but I want to select elements of arr1 based on the index in arr2:
arr1 = [33,66,77,8,99]
arr2 = [2,0,3]
I am using underscore.js but the 0 index is not retrieved (seems to be considered as false):
res = _.filter(arr1, function(value, index){
if(_.contains(arr2, index)){
return index;
}
});
Which returns:
# [77, 8]
How could I fix this, and is there a simpler way to filter using an array of indexes? I am expecting the following result:
# [77, 33, 8]
The simplest way is to use _.map on arr2, like this
console.log(_.map(arr2, function (item) {
return arr1[item];
}));
// [ 77, 33, 8 ]
Here, we iterate the indexes and fetching the corresponding values from arr1 and creating a new array.
Equivalent to the above, but perhaps a bit more advanced, is to use _.propertyOf instead of the anonymous function:
console.log(_.map(arr2, _.propertyOf(arr1)));
// [ 77, 33, 8 ]
If your environment supports ECMA Script 6's Arrow functions, then you can also do
console.log(_.map(arr2, (item) => arr1[item]));
// [ 77, 33, 8 ]
Moreover, you can use the native Array.protoype.map itself, if your target environment supports them, like this
console.log(arr2.map((item) => arr1[item]));
// [ 77, 33, 8 ]
for me the best way to do this is with filter.
let z=[10,11,12,13,14,15,16,17,18,19]
let x=[0,3,7]
z.filter((el,i)=>x.some(j => i === j))
//result
[10, 13, 17]
You are returning index, so in your case 0 treated as false. So you need to return true instead
res = _.filter(arr1, function(value, index){
if(_.contains(arr2, index)){
return true;
}
});
or just return _.contains()
res = _.filter(arr1, function(value, index){
return _.contains(arr2, index);
});
One can use the filter method on the array that one wants to subset. The filter iterates over the array and returns a new one consisting of the items that pass the test. The test is a callback function, in the example below an anonymous arrow function, that accepts required currentValue and optional index parameters. In the example below I used _ as the first parameter since it is not utilized and that way the linter does not highlight it as unused :).
Within the callback function the includes method of array is used on the array that we use as the source of indices to check whether the current index of the arr1 is part of the desired indices.
let arr1 = [33, 66, 77, 8, 99];
let arr2 = [2, 0, 3];
let output = arr1.filter((_, index) => arr2.includes(index));
console.log("output", output);
_.contains returns a boolean. You should return that from the filter predicate, rather than the index because 0 is a falsy value.
res = _.filter(arr1, function(value, index)) {
return _.contains(arr2, index);
});
As an aside, JavaScript arrays have a native filter method so you could use:
res = arr1.filter(function(value, index)) {
return _.contains(arr2, index);
});
Isn't it better to iterate through indices array as main loop?
var arr1 = [33,66,77,8,99]
var arr2 = [2,0,3]
var result = [];
for(var i=0; i<arr2.length; i++) {
var index = arr2[i];
result.push(arr1[index]);
}
console.log(result);
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