In short, is there a way to exit the loop if my condition is met in a functional way?
Let me elaborate.
Let's say I have an array:-
var arr = [4,6,2,24,16,13,88,64,28,39,66,26,9]
and I want to extract the first odd number from arr.
My initial thought was that I could just use .some and get the first element whenever my condition is met but when I went over MDN I quickly found out that it's not as simple as I thought it would be cause .some only returns boolean value.
So, my another approach was to use .filter which would filter out all the odd numbers and grab the first one but doing this will make the loop go through the entire array even though filter has already found the first odd number in the loop. This is okay for small arrays but for arrays with huge elements, it feels that this is quite unnecessary.
Am I missing something with functional technique or is this usually how functional programming goes?
Just for the reference my solution with .some and .filter are:-
var result1, result2;
//Loop ends on the right element but result wrong value
var arr = [4, 6, 2, 24, 16, 13, 88, 64, 28, 39, 66, 26, 9];
result1 = arr.some(function (i) {
return i % 2;
});
//Has right value but loop continues till the end
result2 = arr.filter(function (i) {
return i % 2;
})[0];
You can use some with a variable to store the first odd value.
Fiddle
var arr = [4, 6, 2, 24, 16, 13, 88, 64, 28, 39, 66, 26, 9];
var odd = 0;
arr.some(function(i) {
console.log(i); // To check if this loop over all the elements of array
odd = i; // Assign the value
return i % 2;
});
document.write(odd);
You can use array.prototype.find - included on that page is a polyfill for stupid browsers
usage:
result1 = arr.find(function(i){
return i%2;
});
Try using a while loop
var arr = [4, 6, 2, 24, 16, 13, 88, 64, 28, 39, 66, 26, 9];
var i = 0;
// should break if odd number found,
// `i` would be index of first odd number found in `arr`
while (arr[i] % 2 === 0 && i < arr.length) {
++i;
};
console.log(arr[i])
Related
I am trying to remove even integers from an array. The function I wrote is still returning an index with an even number in it. I'm not sure why I'm getting that kind of behavior. Any thoughts?
let arr = [6, 3, 19, 43, 12, 66, 43];
const removeEvenValues = arr => {
arr.forEach((num, i) => {
if(num % 2 === 0) arr.splice(i, 1);
});
};
removeEvenValues(arr); // arr becomes [3, 19, 43, 66, 43] but should become [3, 19, 43, 43]
Don't splice an array while iterating over it - that'll change it in place. For example, if you start with an array [2, 4, 6], and on the first iteration, remove the item at index 0, the array will then be [4, 6], and you'll go onto the second iteration, where i is 1. You'll then remove the item at the 1st index, which is 6, resulting in the array becoming [4].
Every time an item gets removed, your current method forgets to re-check the new item that fell into the index of the removed item.
It's very confusing. Either use a for loop and start at the end of the array instead, or (even better) use .filter:
let arr = [6, 3, 19, 43, 12, 66, 43];
const removeEvenValues = arr => arr.filter(num => num % 2 !== 0);
console.log(removeEvenValues(arr));
If you have to mutate the existing array (which usually isn't a good idea unless absolutely necessary), then:
let arr = [6, 3, 19, 43, 12, 66, 43];
const removeEvenValues = arr => {
for (let i = arr.length - 1; i >=0; i--) {
if (arr[i] % 2 === 0) {
arr.splice(i, 1);
}
}
return arr;
}
console.log(removeEvenValues(arr));
I built a program that check if there are two common numbers in two different arrays, and then log those numbers. I was able to do that using a simple for loop that goes trough each element of the first array and check if there is an equal element in the second array. Each of the same element in the arrays are stored in a third array called "commonNumbers" which I logged at the end of the program.
const firstNumbers = [12, 45, 6, 78]
const secondNumbers = [6, 7, 12, 45]
let commonNumbers = []
for (let i = 0; i < firstNumbers.length; i++) {
for (let j = 0; j < secondNumbers.length; j++) {
if (firstNumbers[i] === secondNumbers[j]) {
commonNumbers += secondNumbers[j]
}
} }
console.log(commonNumbers)
The result for this example is the seguent:
12456
[Finished in 0.2s]
My question is about the result. I can see that the program actually worked and logged the same element in the arrays (12, 45, 6), but I can't figure out why "commonNumbers" stored the result in such a way that there are no spaces between the numbers.
I would like to clearly see each number.
For example if I call the first element of "commonNumbers" (of index 0):
commonNumbers[0] the result I will get is not going to be "12" as expected, but "1".
Same thing happen if I say: commonNumbers[2] the result is going to be "4", not "6".
Apparently "commonNumbers" array stored the element in a different way I was expecting. How can I solve this, using this "storing" method?
This is because +=, on your array, implicitly convert it to a string, as you can see in the example below, where a Number is summed to an Array.
console.log(typeof([] + 1));
Just use the comfortable .push (read more about push here) method of arrays in order to add the element:
const firstNumbers = [12, 45, 6, 78]
const secondNumbers = [6, 7, 12, 45]
let commonNumbers = []
for (let i = 0; i < firstNumbers.length; i++) {
for (let j = 0; j < secondNumbers.length; j++) {
if (firstNumbers[i] === secondNumbers[j]) {
commonNumbers.push(secondNumbers[j]);
}
} }
console.log(commonNumbers)
As a (final) side note, there are several other ways to accomplish your task, the cleverest you can probably go with is filter. You may also would take care of eventual duplicates, since if your input array has two identical numbers the commonsNumber result will contain both, which might be unintended.
The "definitive" clever solution that tries to also take care of duplicates and to loop the shorter array would be something like this:
// Inputs with duplicates, and longer array on second case.
const firstNumbers = [12, 45, 6, 78, 12, 12, 6, 45];
const secondNumbers = [6, 7, 12, 45, 45, 45, 12, 6, 99, 19, 5912, 9419, 1, 4, 8, 6, 52, 45];
// Performance: look for duplicates starting from the shortest array. Also, make a set to remove duplicate items.
const [shortestArray, longestArray] = firstNumbers.length < secondNumbers.length ? [firstNumbers, secondNumbers] : [secondNumbers, firstNumbers];
// Remove duplicates.
const dedupes = [...new Set(shortestArray)];
// Find commomn items using filter.
const commons = dedupes.filter(i => longestArray.indexOf(i) > -1);
console.log('commons is', commons);
Don't get me wrong, the solution is fine, just wanted to add "something" to the boilerplate, to take care of eventual additional scenarios.
const firstNumbers = [12, 45, 6, 78]
const secondNumbers = [6, 7, 12, 45]
let commonNumbers = []
for (let i = 0; i < firstNumbers.length; i++) {
for (let j = 0; j < secondNumbers.length; j++) {
if (firstNumbers[i] === secondNumbers[j]) {
commonNumbers.push(secondNumbers[j])
}
} }
The push method appends values to an array.
You seem to be looking for array.prototype.push (mdn). E.g.:
const firstNumbers = [12, 45, 6, 78]
const secondNumbers = [6, 7, 12, 45]
let commonNumbers = []
for (let i = 0; i < firstNumbers.length; i++)
for (let j = 0; j < secondNumbers.length; j++)
if (firstNumbers[i] === secondNumbers[j])
commonNumbers.push(secondNumbers[j]);
console.log(commonNumbers); // as an array
console.log(commonNumbers.join(', '));
why "commonNumbers" stored the result in such a way that there are no spaces between the numbers.
The + operator will try to cast its operands to compatible types. In this case, that is a string, where empty arrays [] are cast to empty strings '', and numbers 3 are cast to the corresponding string '3'. E.g. [] + 3 is the string '3'.
console.log([], typeof []);
console.log(3, typeof 3);
console.log([] + 3, typeof ([] + 3));
We have array of numbers, we need to find the total number of ways that we can remove one number in the array if removing that, will sort the array.
For example if we have [3,4,5,4] we should return 2 because if we remove 5 or the second 4 our array will be sorted.
But if we get something like [4,5,2,3,4] we should return 0 because removing any of them will not sort the array.
I believe that this is something related to Longest increasing subsequence
Correct me if I'm wrong, but this should work like this :
We should find the longest increasing subsequence and delete everything not in that subsequence.
With that in mind, I used some function like this to find the LIS :
function findSubsequence(arr){
var allSubsequence = [],
longestSubsequence = null,
longestSubsequenceLength = -1;
for(var i=0;i<arr.length;i++){ //i=1
var subsequenceForCurrent = [arr[i]],
current = arr[i],
lastElementAdded = -1;
for(var j=i;j<arr.length;j++){
var subsequent = arr[j];
if((subsequent > current) && (lastElementAdded<subsequent)){
subsequenceForCurrent.push(subsequent);
lastElementAdded = subsequent;
}
}
allSubsequence.push(subsequenceForCurrent);
}
for(var i in allSubsequence){
var subs = allSubsequence[i];
if(subs.length>longestSubsequenceLength){
longestSubsequenceLength = subs.length;
longestSubsequence = subs;
}
}
return longestSubsequence;
}
(function driver(){
var sample = [87,88,91, 10, 22, 9,92, 94, 33, 21, 50, 41, 60, 80];
console.log(findSubsequence(sample));
})();
But this give me the highest numbers, I'm not sure how should I remove one of them to keep the array sort and find all possible ways.
Any Idea?
That approach seems a bit complicated. I think it would be clearer and less resource-heavy to use a brute force approach: for every item in the array, try removing it, and then check to see if the array is sorted afterwards. But don't use sort to check if it's sorted (that has O(N log N) complexity), instead, just check to see that every item in the array is the same or greater than the previous one (O(N)):
const checkSorted = arr => arr.every((num, i, arr) => i === 0 || num >= arr[i - 1]);
const checkRemovalCount = arr => arr.reduce((countSoFar, _, i, arr) => {
const removedArr = [...arr.slice(0, i), ...arr.slice(i + 1)];
return countSoFar + checkSorted(removedArr);
}, 0);
console.log(checkRemovalCount([3,4,5,4]));
console.log(checkRemovalCount([4,5,2,3,4]));
console.log(checkRemovalCount([87,88,91, 10, 22, 9,92, 94, 33, 21, 50, 41, 60, 80]));
You can remove highest number using Math Library.
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<script type="text/javascript">
var sample = [87,88,91, 10, 22, 9,92, 94, 33, 21, 50, 41, 60, 80];
sample.sort(function(a, b){return a - b});
list = remove_highest(sample)
console.log(list) // [9, 10, 21, 22, 33, 41, 50, 60, 80, 87, 88, 91, 92]
function remove_highest(list) {
return list.filter(function(n) { return n != Math.max.apply( Math, list ) })
}
</script>
</body>
</html>
I have three sorted array I need to find top five "5" element from these array .I am able to find first two element largest element .how I will find other ?
can you suggest how we can find other 3 element ?
here is my code
var maxArray=[];
var array1=[2,7,12,23,40,44,67,88,102]
var array2=[3,12,14,17,23,40,41,67,108]
var array3=[8,12,23,40,59,86,119,130]
var firstMax=array1[array1.length-1];
var secondMax=array2[array2.length-1];
alert(array1[array1.length-1]);
if(array1[array1.length-1]>array2[array2.length-1] && array1[array1.length-1]>array3[array3.length-1]){
maxArray.push(array1[array1.length-1]) ;
firstMax=array1[array1.length-1];
if(array2[array2.length-1]>array3[array3.length-1]){
secondMax=array2[array2.length-1];
}else {
secondMax=array3[array3.length-1];
}
}else if(array2[array2.length-1]>array1[array1.length-1]&& array2[array2.length-1]>array3[array3.length-1]){
maxArray.push(array1[array2.length-1])
firstMax=array2[array2.length-1];
if(array1[array1.length-1]>array3[array3.length-1]){
secondMax=array1[array1.length-1];
}else {
secondMax=array3[array3.length-1];
}
}else{
maxArray.push(array3[array3.length-1])
firstMax=array3[array3.length-1];
if(array2[array2.length-1]>array1[array1.length-1]){
secondMax=array2[array2.length-1];
}else {
secondMax=array1[array1.length-1];
}
}
maxArray.push(secondMax)
alert(maxArray)
fiddle
http://jsfiddle.net/9vsjm8uh/
jsFiddle (yep, even better without jQuery, thanks #Rajacsp)
var array1 = [2, 7, 12, 23, 40, 44, 67, 88, 102]
var array2 = [3, 12, 14, 17, 23, 40, 41, 67, 108]
var array3 = [8, 12, 23, 40, 59, 86, 119, 130]
var flatArray = array1.concat(array2).concat(array3);
flatArray.sort(function sortNumber(a, b) { return b - a; });
var maxArray = flatArray.slice(0, 5);
alert(maxArray); // 130,119,108,102,88
I would suggest the following idea:
Since you are looking for the top 5 values, they will, at worst case, all be in the same list. Thus, there are at most 5 * 3 = 15 values to check.
Then, you can take the 5 highest values from each list (which should be trivial if the list is already sorted), and then put them in another list. Now you have a list of the 15, and you want to find the top 5 values from this list. There are different ways to do this - you could sort the list, then take the top 5 values, or you can simply iterate through the list, finding the max each time.
Combine all of the arrays, sort them, then get the last 5 values.
var total = array1.concat(array2, array3);
total = total.sort(function(a,b){return a-b});
//Now total[length-5] is the 5th largest value
//total[length-4] is the 4th largest and so on
Plain Javascript (no libraries added):
var array1=[2,7,12,23,40,44,67,88,102];
var array2=[3,12,14,17,23,40,41,67,108];
var array3=[8,12,23,40,59,86,119,130];
alert(getTopFive(array1, array2, array3));
function getTopFive(ar1, ar2, ar3){
var finalArray = array1.concat(array2).concat(array3);
finalArray.sort(function sortInverse(a,b) { return b - a; });
return finalArray.slice(0, 5);
}
I have a need to add or prepend elements at the beginning of an array.
For example, if my array looks like below:
[23, 45, 12, 67]
And the response from my AJAX call is 34, I want the updated array to be like the following:
[34, 23, 45, 12, 67]
Currently I am planning to do it like this:
var newArray = [];
newArray.push(response);
for (var i = 0; i < theArray.length; i++) {
newArray.push(theArray[i]);
}
theArray = newArray;
delete newArray;
Is there a better way to do this? Does JavaScript have any built-in functionality that does this?
The complexity of my method is O(n) and it would be really interesting to see better implementations.
Use unshift. It's like push, except it adds elements to the beginning of the array instead of the end.
unshift/push - add an element to the beginning/end of an array
shift/pop - remove and return the first/last element of an array
A simple diagram...
unshift -> [array] <- push
shift <- [array] -> pop
and chart:
add remove start end
push X X
pop X X
unshift X X
shift X X
Check out the MDN Array documentation. Virtually every language that has the ability to push/pop elements from an array will also have the ability to unshift/shift (sometimes called push_front/pop_front) elements, you should never have to implement these yourself.
As pointed out in the comments, if you want to avoid mutating your original array, you can use concat, which concatenates two or more arrays together. You can use this to functionally push a single element onto the front or back of an existing array; to do so, you need to turn the new element into a single element array:
const array = [3, 2, 1]
const newFirstElement = 4
const newArray = [newFirstElement].concat(array) // [ 4, 3, 2, 1 ]
console.log(newArray);
concat can also append items. The arguments to concat can be of any type; they are implicitly wrapped in a single-element array, if they are not already an array:
const array = [3, 2, 1]
const newLastElement = 0
// Both of these lines are equivalent:
const newArray1 = array.concat(newLastElement) // [ 3, 2, 1, 0 ]
const newArray2 = array.concat([newLastElement]) // [ 3, 2, 1, 0 ]
console.log(newArray1);
console.log(newArray2);
var a = [23, 45, 12, 67];
a.unshift(34);
console.log(a); // [34, 23, 45, 12, 67]
With ES6, use the spread operator ...:
Demo
var arr = [23, 45, 12, 67];
arr = [34, ...arr]; // RESULT : [34,23, 45, 12, 67]
console.log(arr)
Another way to do that is through concat:
var arr = [1, 2, 3, 4, 5, 6, 7];
console.log([0].concat(arr));
The difference between concat and unshift is that concat returns a new array. The performance between them could be found here.
function fn_unshift() {
arr.unshift(0);
return arr;
}
function fn_concat_init() {
return [0].concat(arr)
}
Here is the test result:
Quick Cheatsheet:
The terms shift/unshift and push/pop can be a bit confusing, at least to folks who may not be familiar with programming in C.
If you are not familiar with the lingo, here is a quick translation of alternate terms, which may be easier to remember:
* array_unshift() - (aka Prepend ;; InsertBefore ;; InsertAtBegin )
* array_shift() - (aka UnPrepend ;; RemoveBefore ;; RemoveFromBegin )
* array_push() - (aka Append ;; InsertAfter ;; InsertAtEnd )
* array_pop() - (aka UnAppend ;; RemoveAfter ;; RemoveFromEnd )
Using ES6 destructuring (avoiding mutation off the original array):
const newArr = [item, ...oldArr]
Without Mutating
Actually, all unshift/push and shift/pop mutate the source array.
The unshift/push add an item to the existed array from begin/end and shift/pop remove an item from the beginning/end of an array.
But there are few ways to add items to an array without a mutation. the result is a new array, to add to the end of array use below code:
const originArray = ['one', 'two', 'three'];
const newItem = 4;
const newArray = originArray.concat(newItem); // ES5
const newArray2 = [...originArray, newItem]; // ES6+
To add to begin of original array use below code:
const originArray = ['one', 'two', 'three'];
const newItem = 0;
const newArray = (originArray.slice().reverse().concat(newItem)).reverse(); // ES5
const newArray2 = [newItem, ...originArray]; // ES6+
With the above way, you add to the beginning/end of an array without a mutation.
You have an array: var arr = [23, 45, 12, 67];
To add an item to the beginning, you want to use splice:
var arr = [23, 45, 12, 67];
arr.splice(0, 0, 34)
console.log(arr);
Cheatsheet to prepend new element(s) into the array
1. Array#unshift
const list = [23, 45, 12, 67];
list.unshift(34);
console.log(list); // [34, 23, 45, 12, 67];
2. Array#splice
const list = [23, 45, 12, 67];
list.splice(0, 0, 34);
console.log(list); // [34, 23, 45, 12, 67];
3. ES6 spread...
const list = [23, 45, 12, 67];
const newList = [34, ...list];
console.log(newList); // [34, 23, 45, 12, 67];
4. Array#concat
const list = [23, 45, 12, 67];
const newList = [32].concat(list);
console.log(newList); // [34, 23, 45, 12, 67];
Note: In each of these examples, you can prepend multiple items by providing more items to insert.
If you need to continuously insert an element at the beginning of an array, it is faster to use push statements followed by a call to reverse, instead of calling unshift all the time.
Benchmark test: http://jsben.ch/kLIYf
Using splice we insert an element to an array at the begnning:
arrName.splice( 0, 0, 'newName1' );
If you want to push elements that are in an array at the beginning of your array, use <func>.apply(<this>, <Array of args>):
const arr = [1, 2];
arr.unshift.apply(arr, [3, 4]);
console.log(arr); // [3, 4, 1, 2]