Related
So, I did this in order to find the second biggest value in an array (I know there are a lot of answers out there, I just want to know why this approach fails)
With a first reduce() method on the number array I find the largest number, then using a second reduce() method I tried to use an if statement to check return the biggest number only if the compared numbers are not the previous biggest one found. This is the code:
const arr = [1,6,2,7,3,9,5,8];
const biggest = arr.reduce((a,b)=> {
return Math.max(a,b)
})
console.log(biggest)
const secondBiggest = arr.reduce((a,b)=>{
if(a!= biggest && b!= biggest){
return Math.max(a,b)
}
})
console.log(secondBiggest) // --> NAN
In every iteration you need to return something from reduce function. so currently you just return when (a!= biggest && b!= biggest) is true. so you need to return the original value of accumulator a when the condition doesn't match as well (return a).
Learn more about reduce()
const arr = [1,6,2,7,3,9,5,8];
const biggest = arr.reduce((a,b)=> {
return Math.max(a,b)
})
console.log(biggest)
const secondBiggest = arr.reduce((a,b)=>{
if(a!= biggest && b!= biggest){
return Math.max(a,b)
}
return a; // if you don't return anything during the next iteration the accumulator will have `undefined`.
})
console.log(secondBiggest) // --> NAN
You want return your accumulator as is if the current one is the biggest
const arr = [1, 6, 2, 7, 3, 9, 5, 2];
const biggest = Math.max([...arr])
console.log(biggest)
const secondBiggest = arr.reduce((accumulator, current) => {
if (current != biggest) {
return Math.max(accumulator, b)
}
return a
})
console.log(secondBiggest)
There is this function:
function countup(n) {
if (n < 1) {
return [];
} else {
const countArray = countup(n - 1);
countArray.push(n);
return countArray;
}
}
console.log(countup(5));
How is [] being pushed first? From the code, it looks like it is being counted down from n. Can someone explain?
Bonus question: Why write like this when I can write:
function countup(n){
let answer = []
for (let i = 1; i <= n; i++){
(i<n) ? answer.push(i)
: answer.push(n)
}
return answer
}
console.log(countup(5));
which is a shorter function. thank you in advance!
Even though the numbers are in descending order starting from n, they are actually being pushed smallest number first. This is because before the push() operation can happen we keep going down in the recursion stack when we call countup(n - 1) every layer of the recursion. This is why we reach a point where n < 1 i.e. 0 where an empty array is returned.
Next, we encounter the first array.push() operation and so the first number that is pushed into the array is actually 1 and not n. Next, the recursion layers start winding up and we push numbers 2, 3, and so on till n.
Yes you can achieve the same using a traditional for loop, but I guess they just want to explain how recursion works.
To understand recursions, sometimes you need to follow the execution of the code manually. Now the following line causes the recursive call and subtracts one from the number and then passes it to the recursive call.
const countArray = countup(n - 1);
Now imagine, if you passed 5 to the initial function call like so:
countup(5);
As 5 is not less than 1, the else block will be executed. The first line in the else block is the recursive call. So when your program encounters the recursive call, it stops execution of the current function until that recursive function call is concluded/returned. So the first recursive call will be:
const countArray = countup(4);
consequently, the same process will be repeated until n equals 0. As 0 is smaller than 1, the if condition will evaluate to true. and it will return an empty array.
After the recursive call, it pushes the number to the array returned by recursive call. so the array at that point will contain [0] and then
[0, 1] and it will keep adding numbers till the all recursive calls have been computed and then it will execute the rest of the intial function call.
Often times, recursion can be replaced by loops but thats not the case always. As a programmer one should be aware of this important topic.
Since countup() is fully divided by an if statement that depends on n, let's first see what exectutes for different vales of n.
To make it a lot easier to follow, we'll append our current n to countArray's variable name:
n == 5:
const countArray5 = countup(4);
countArray5.push(5);
return countArray5;
⋮
n == 1:
const countArray1 = countup(0);
countArray1.push(1);
return countArray1;
n == 0:
return [];
Now let's sequentially expand each inner call to countup(n):
countup(5) {
const countArray5 = countup(4);
countArray5.push(5);
return countArray5;
}
countup(5) {
const countArray5 = countup(4) {
const countArray4 = countup(3);
countArray4.push(4);
return countArray4;
};
countArray5.push(5);
return countArray5;
}
Expanding until countup(0):
countup(5) {
const countArray5 = countup(4) {
const countArray4 = countup(3) {
const countArray3 = countup(2) {
const countArray2 = countup(1) {
const countArray1 = countup(0) // countup(0) returns [] so countArray1 = [];
countArray1.push(1); // Then push '1' to countArray1;
return countArray1; // Return [1] at counterArray2 = countup(1) above
};
countArray2.push(2); // countArray2 was [1], now push '2' to make it [1,2]
return countArray2; // Return [1,2] at countArray3 = countup(2) above
};
countArray3.push(3); // Push '3' to countArray3 => [1,2,3]
return countArray3; // return [1,2,3] at countArray4 = countup(3)
};
countArray4.push(4); // Push '4' to countArray4 => [1,2,3,4]
return countArray4; // Return [1,2,3,4] at countArray5 = countup(4)
};
countArray5.push(5); // Push '5' to countArray5 => [1,2,3,4,5]
return countArray5; // countup(5) returns [1,2,3,4,5]
}
I want to know that How can we print the elements of an array in a alternate order with the help of function in javascript?
array = [6,20,99,10,60,31,05,08];
result = [6,99,60,05]
You could use .filter - a high-order function in javascript. By using filter you can filter your elements via their index. If the index i modulo 2 is zero (ie !(i % 2)) then you can keep the element, and thus return true:
const arr = [6,20,99,10,60,31,05,08],
res = arr.filter((_, i) => !(i % 2));
console.log(res);
We want to traverse the array and use decent time complexity. To avoid looping more than once let's make our function do it in a single go. So we'll use an array helper. We also only want this to do something every other index. So we'll modulo it by 2, and if it is 0 we'll send it to the function. To make this have the same footprint as other common array functions we'll make it pass the same arguments it receives from forEach to the Function that gets passed.
function everyOther (array, fn) {
array.forEach(function (value, index, array) {
if (!(index % 2)) fn(value, index, array);
})
}
Now we just call it and do what we want!
everyOther([1,2,3], function (value) { console.log(value) }); // prints 1, 3
We could even make this strictly a print only of every other by wrapping it in a closure
function printEveryOther (array) {
everyOther(array, function (value) { console.log(value) });
}
printEveryOther([1,2,3]) // 1, 3
Now you have an adaptable function that has a familiar footprint and even can be made to do other things!
Things that were made use of in this example:
Function declarations
Anonymous Functions
Array.prototype.forEach()
Modulo operator
Okay now for some spice thanks to some more recent additions to JavaScript:
const everyOther = (a, f) => a.forEach((v, i) => !(i%2) && f(v,i,a));
const mapEveryOther = (a, f) => {
const r = [];
everyOther(a, (v, i) => r.push(f(v,i,a)));
return r;
}
And now we've made another function entirely that instead returns an array
const doubleEveryOther = a => mapEveryOther(a, a => a + a);
doubleEveryOther([1,2,3]) // [2,6]
Concepts used:
Arrow Functions
Closures
There's still lots more to have fun with. Happy learning!
Use for loop and increment i by 2
let array = [2, 20, 5, 66, 5, 98, 4, 6];
function alternate(array) {
for (i = 0; i < array.length; i += 2) {
console.log((i + 1) + ": " + array[i]);
}
}
alternate(array);
I was asked in an interview to write a program/algo to sort an array of number using recursion.
Though I vaguely answered it, I tried and came up with following code:
You can use following JSFiddle link to play around.
function sort(arr) {
if (arr.length === 2) {
const v1 = arr[0];
const v2 = arr[1];
const isGreater = (
(isString(v1) && isString(v2) && v1.toString().toLocaleCompare(v2) > 0) ||
(isNumber(v1) && isNumber(v2) && v1 > v2)
);
return isGreater ? [ v2, v1 ] : [ v1, v2 ];
} else {
const last = arr.pop();
const ret = sort(arr);
const newLast = ret.peekLast();
if (newLast < last) {
return [ ...ret, last ];
} else {
return sort( [ last, ...ret ] );
}
}
}
function isString(value) { return typeof value === 'string'; }
function isNumber(value) { return Number.isFinite(value); }
Array.prototype.peekLast = function () { return this.slice().pop(); }
//console.log(sort([1,2,3,4,5]))
console.log(sort([5,4,3,2,1]))
The algo I implemented is:
Take the array and check if its length is greater than 2.
If yes,
Remove last element and store it in a variable.
Again call same function without last element till it has 2 items.
Accept array returned from recursive call and peek the last element.
If newLast value is greater than previousLast
Push previousLast as first element and again call itself with this array.
If not, push previousLast to array and return it.
Else,
For number and string check equality and return correct order.
For anything else, return same value
Question is, is there a better way to implement (algo wise)?
Note: I'm not expecting code improvements. Objective of this question is improvement in algo part or any general stuff I have missed.
I also know, current code does not support:
Sort order. It will sort ascending only.
May break for Date objects, and does not support Objects in general.
Thanks!
I think most interviewers would expect you to respond with quicksort or merge sort (or both) given that question. Of the two, quicksort, is easier to remember and recreate in a pinch because the merge step of merge sort is easy to mess up.
Quicksort is a really beautiful algorithm and is a natural fit for javascript's functional tools. It is worth really understanding if you'll be doing interviews:
const arr = [6, 1, 5, 3, 9, 6, 7, 10, 16, 4, 0, 12, 2]
function qsort(arr){
if (arr.length < 2) return arr
// choose a pivot, p
// the choice of pivot can effect worst-case performance
// for this, we'll just use the first element.
const [p, ...rest] = arr
// partition array into element greater and lesser that the pivot
// this can be optimized so you don't loop through the array twice
const low = rest.filter(n => n <= p)
const high = rest.filter(n => n > p)
// recurse on both partitions and reassemble as recursion unwinds
return [...qsort(low), p, ...qsort(high)]
}
console.log(qsort(arr).join(', '))
I see a vein of intermediate value creation that is not inconsequential.
peekLast calls Array.prototype.slice which makes a copy of the array. You copy an entire array just to return the last element.
Array.prototype.peekLast = function () { return this.slice().pop(); }
Array.prototype.peekLast = function () { return this[this.length]; }
This gives you the same result every time without the need to copy.
Use of spread arguments in expressions like [ ...arr, x ] copies arr entirely.
arr.concat([ x ]) does the same thing without making copy (or mutation) of arr
You call peekLast and use ...x once per element in the input. Calling sort on a list of just 100 items will copy over 10,000 elements, for these operations alone. A list of just 1,000 items will copy over 1,000,000 elements. Room for algorithm improvment? For sure.
Mark Meyer starts you off on the right foot. If you're going to use recursion, it's best writing your program in functional style, as it will yield the best results. Mixing imperative style (statements, mutations, reassignments, other side effects, etc) with recursion is a recipe for a migraine.
Mark's algorithm, however great a "code improvement", your question is asking for "algorithm improvements". Under this lens, Mark's algorithm suffers from similar intermediate value creation by use of many ...x expressions.
Another lurking offense is the double use of .filter on the same array, rest. This creates an inefficient process as it iterates entirely through rest two (2) times per element. This is a symptom of reaching for low-hanging built-in functions that do close to what you want, but not exactly what you want. A better function would iterate through the array once and return both results.
The inefficiencies in Mark's program are mostly forgivable because of the dramatic improvement in code quality. His program is much more readable than yours because he's using functional style, which is where recursion comes from. The inefficiencies are also very easy to fix, so maybe that's an exercise for you?
Let's see if that gets your brain going. We'll see what answers other people submit before smothering you with too much information.
Your code will fail if we have duplicate elements because of this line.
if (newLast < last) {
It will go into infinite recursion
Refer the snippet with the duplicate array passed as input
function sort(arr) {
if (arr.length === 2) {
const v1 = arr[0];
const v2 = arr[1];
const isGreater = (
(isString(v1) && isString(v2) && v1.toString().toLocaleCompare(v2) > 0) ||
(isNumber(v1) && isNumber(v2) && v1 > v2)
);
return isGreater ? [ v2, v1 ] : [ v1, v2 ];
} else {
const last = arr.pop();
const ret = sort(arr);
const newLast = ret.peekLast();
debugger;
if (newLast < last) {
return [ ...ret, last ];
} else {
return sort( [ last, ...ret ] );
}
}
}
function isString(value) { return typeof value === 'string'; }
function isNumber(value) { return Number.isFinite(value); }
Array.prototype.peekLast = function () { return this.slice().pop(); }
//console.log(sort([1,2,3,4,5]))
console.log(sort([3,3,5,2]))
this one work for me to sort an array recursively:
var array = [3,1,8,2,4,9,16,28];
const sum = (arr, i=0)=> {
if(i === arr.length) return arr;
if(arr[i+1] < arr[i]){
const x = arr[i+1];
arr[i+1] = arr[i];
arr[i] = x;
}
return sum(arr,i+1);
}
console.log(sum(array))
function swap(arr, firstIndex, secondIndex){
let a= arr[firstIndex];
arr[firstIndex] = arr[secondIndex];
arr[secondIndex] = a;
return arr;
}
function sortArr(arr, index=0){
if(index == arr.length) return arr;
for(let i=0;i<arr.length; i++){
if(arr[i] > arr[i+1]){
arr = swap(arr, i, i+1);
}
}
return sortArr(arr, index+1);
}
console.log(sortArr([4,1,3,2,0]));
function quicksort(num){
if (num.length < 2){
return num
}
let pivot = num[0];
let slicedArr = num.slice(1);
let left = [];
let right = [];
for(let i = 0; i < slicedArr.length; i++){
if(slicedArr[i] <= pivot){
left.push(slicedArr[i])
}else{
right.push(slicedArr[i])
}
}
return [...quicksort(left), pivot, ...quicksort(right)]
}
I have a JavaScript array like this:
var myData=['237','124','255','124','366','255'];
I need the array elements to be unique and sorted:
myData[0]='124';
myData[1]='237';
myData[2]='255';
myData[3]='366';
Even though the members of array look like integers, they're not integers, since I have already converted each to be string:
var myData[0]=num.toString();
//...and so on.
Is there any way to do all of these tasks in JavaScript?
This is actually very simple. It is much easier to find unique values, if the values are sorted first:
function sort_unique(arr) {
if (arr.length === 0) return arr;
arr = arr.sort(function (a, b) { return a*1 - b*1; });
var ret = [arr[0]];
for (var i = 1; i < arr.length; i++) { //Start loop at 1: arr[0] can never be a duplicate
if (arr[i-1] !== arr[i]) {
ret.push(arr[i]);
}
}
return ret;
}
console.log(sort_unique(['237','124','255','124','366','255']));
//["124", "237", "255", "366"]
You can now achieve the result in just one line of code.
Using new Set to reduce the array to unique set of values.
Apply the sort method after to order the string values.
var myData=['237','124','255','124','366','255']
var uniqueAndSorted = [...new Set(myData)].sort()
UPDATED for newer methods introduced in JavaScript since time of question.
This might be adequate in circumstances where you can't define the function in advance (like in a bookmarklet):
myData.sort().filter(function(el,i,a){return i===a.indexOf(el)})
Here's my (more modern) approach using Array.protoype.reduce():
[2, 1, 2, 3].reduce((a, x) => a.includes(x) ? a : [...a, x], []).sort()
// returns [1, 2, 3]
Edit: More performant version as pointed out in the comments:
arr.sort().filter((x, i, a) => !i || x != a[i-1])
function sort_unique(arr) {
return arr.sort().filter(function(el,i,a) {
return (i==a.indexOf(el));
});
}
How about:
array.sort().filter(function(elem, index, arr) {
return index == arr.length - 1 || arr[index + 1] != elem
})
This is similar to #loostro answer but instead of using indexOf which will reiterate the array for each element to verify that is the first found, it just checks that the next element is different than the current.
Try using an external library like underscore
var f = _.compose(_.uniq, function(array) {
return _.sortBy(array, _.identity);
});
var sortedUnique = f(array);
This relies on _.compose, _.uniq, _.sortBy, _.identity
See live example
What is it doing?
We want a function that takes an array and then returns a sorted array with the non-unique entries removed. This function needs to do two things, sorting and making the array unique.
This is a good job for composition, so we compose the unique & sort function together. _.uniq can just be applied on the array with one argument so it's just passed to _.compose
the _.sortBy function needs a sorting conditional functional. it expects a function that returns a value and the array will be sorted on that value. Since the value that we are ordering it by is the value in the array we can just pass the _.identity function.
We now have a composition of a function that (takes an array and returns a unique array) and a function that (takes an array and returns a sorted array, sorted by their values).
We simply apply the composition on the array and we have our uniquely sorted array.
This function doesn't fail for more than two duplicates values:
function unique(arr) {
var a = [];
var l = arr.length;
for(var i=0; i<l; i++) {
for(var j=i+1; j<l; j++) {
// If a[i] is found later in the array
if (arr[i] === arr[j])
j = ++i;
}
a.push(arr[i]);
}
return a;
};
Here is a simple one liner with O(N), no complicated loops necessary.
> Object.keys(['a', 'b', 'a'].reduce((l, r) => l[r] = l, {})).sort()
[ 'a', 'b' ]
Explanation
Original data set, assume its coming in from an external function
const data = ['a', 'b', 'a']
We want to group all the values onto an object as keys as the method of deduplication. So we use reduce with an object as the default value:
[].reduce(fn, {})
The next step is to create a reduce function which will put the values in the array onto the object. The end result is an object with a unique set of keys.
const reduced = data.reduce((l, r) => l[r] = l, {})
We set l[r] = l because in javascript the value of the assignment expression is returned when an assignment statement is used as an expression. l is the accumulator object and r is the key value. You can also use Object.assign(l, { [r]: (l[r] || 0) + 1 }) or something similar to get the count of each value if that was important to you.
Next we want to get the keys of that object
const keys = Object.keys(reduced)
Then simply use the built-in sort
console.log(keys.sort())
Which is the set of unique values of the original array, sorted
['a', 'b']
The solution in a more elegant way.
var myData=['237','124','255','124','366','255'];
console.log(Array.from(new Set(myData)).sort((a,b) => a - b));
I know the question is very old, but maybe someone will come in handy
A way to use a custom sort function
//func has to return 0 in the case in which they are equal
sort_unique = function(arr,func) {
func = func || function (a, b) {
return a*1 - b*1;
};
arr = arr.sort(func);
var ret = [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (func(arr[i-1],arr[i]) != 0)
ret.push(arr[i]);
}
}
return ret;
}
Example: desc order for an array of objects
MyArray = sort_unique(MyArray , function(a,b){
return b.iterator_internal*1 - a.iterator_internal*1;
});
No redundant "return" array, no ECMA5 built-ins (I'm pretty sure!) and simple to read.
function removeDuplicates(target_array) {
target_array.sort();
var i = 0;
while(i < target_array.length) {
if(target_array[i] === target_array[i+1]) {
target_array.splice(i+1,1);
}
else {
i += 1;
}
}
return target_array;
}
I guess I'll post this answer for some variety. This technique for purging duplicates is something I picked up on for a project in Flash I'm currently working on about a month or so ago.
What you do is make an object and fill it with both a key and a value utilizing each array item. Since duplicate keys are discarded, duplicates are removed.
var nums = [1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10];
var newNums = purgeArray(nums);
function purgeArray(ar)
{
var obj = {};
var temp = [];
for(var i=0;i<ar.length;i++)
{
obj[ar[i]] = ar[i];
}
for (var item in obj)
{
temp.push(obj[item]);
}
return temp;
}
There's already 5 other answers, so I don't see a need to post a sorting function.
// Another way, that does not rearrange the original Array
// and spends a little less time handling duplicates.
function uniqueSort(arr, sortby){
var A1= arr.slice();
A1= typeof sortby== 'function'? A1.sort(sortby): A1.sort();
var last= A1.shift(), next, A2= [last];
while(A1.length){
next= A1.shift();
while(next=== last) next= A1.shift();
if(next!=undefined){
A2[A2.length]= next;
last= next;
}
}
return A2;
}
var myData= ['237','124','255','124','366','255','100','1000'];
uniqueSort(myData,function(a,b){return a-b})
// the ordinary sort() returns the same array as the number sort here,
// but some strings of digits do not sort so nicely numerical.
function sort() only is only good if your number has same digit, example:
var myData = ["3","11","1","2"]
will return;
var myData = ["1","11","2","3"]
and here improvement for function from mrmonkington
myData.sort().sort(function(a,b){return a - b;}).filter(function(el,i,a){if(i==a.indexOf(el) & el.length>0)return 1;return 0;})
the above function will also delete empty array and you can checkout the demo below
http://jsbin.com/ahojip/2/edit
O[N^2] solutions are bad, especially when the data is already sorted, there is no need to do two nested loops for removing duplicates. One loop and comparing to the previous element will work great.
A simple solution with O[] of sort() would suffice. My solution is:
function sortUnique(arr, compareFunction) {
let sorted = arr.sort(compareFunction);
let result = sorted.filter(compareFunction
? function(val, i, a) { return (i == 0 || compareFunction(a[i-1], val) != 0); }
: function(val, i, a) { return (i == 0 || a[i-1] !== val); }
);
return result;
}
BTW, can do something like this to have Array.sortUnique() method:
Array.prototype.sortUnique = function(compareFunction) {return sortUnique(this, compareFunction); }
Furthermore, sort() could be modified to remove second element if compare() function returns 0 (equal elements), though that code can become messy (need to revise loop boundaries in the flight). Besides, I stay away from making my own sort() functions in interpreted languages, since it will most certainly degrade the performance. So this addition is for the ECMA 2019+ consideration.
The fastest and simpleness way to do this task.
const N = Math.pow(8, 8)
let data = Array.from({length: N}, () => Math.floor(Math.random() * N))
let newData = {}
let len = data.length
// the magic
while (len--) {
newData[data[len]] = true
}
var array = [2,5,4,2,5,9,4,2,6,9,0,5,4,7,8];
var unique_array = [...new Set(array)]; // [ 2, 5, 4, 9, 6, 0, 7, 8 ]
var uniqueWithSorted = unique_array.sort();
console.log(uniqueWithSorted);
output = [ 0, 2, 4, 5, 6, 7, 8, 9 ]
Here, we used only Set for removing duplicity from the array and then used sort for sorting array in ascending order.
I'm afraid you can't combine these functions, ie. you gotta do something like this:-
myData.unique().sort();
Alternatively you can implement a kind of sortedset (as available in other languages) - which carries both the notion of sorting and removing duplicates, as you require.
Hope this helps.
References:-
Array.sort
Array.unique