How does this recursive function end? - javascript

This is from nodeschool's functional javascript workshop. Here is the code as it appears there:
function toUpperArray(items) {
if (!items.length) return [] // end condition
var head = items[0] // item to operate
head = head.toUpperCase() // perform action
var tail = items.slice(1) // next
return [head].concat(toUpperArray(tail)) // recursive step
}
toUpperArray(['hello', 'world']) // => ['HELLO', 'WORLD']
I don't understand how the "end condition" works. I think that conditional is looking for the items.length to be 0, but then it returns an empty array? I have tried running this by having it return nothing, which returns undefined thus adds undefined to the final array, but I am not sure why returning an empty array fixes this. I would expect the final item in the final array to be an empty array.
Also, I have never seen a conditional that didn't use curly braces. Is that significant?

When the array is empty. i.e. items.length == 0. The below condition is short form of != 0 because 0 is a false value in javascript, not of 0 should be true.
if (!items.length) return [];

This is because of concat functions which called on Array and with an Array as argument produces an Array as result. Basically you can see it in this way:
the upper array of an empty array is an empty array (base case)
the upper array of an array with at least one element (think of it as element,[array]) is element.toUpperCase() concatenated with the trailing part of the array through the recursive call (recursive step)
Basically you have an array data = [e1, e2, ..., en] and a function f(x). You want to return [f(e1), f(e2), ..., f(en)] so you basically apply the function on the first element on the array and concatenate the result with the value returned from the same recursive function on the same array without the first element.

When the items.length will be eqal to 0 (false), the function will return an empty array and will go up the recursion call stack. Here is a couple way we could have written this condition:
if(!items.length) //true
if(items.length == 0) //true
if(items.length == false) //true
For the conditions without curly braces. It does the same thing except that it only takes the current line or the next line as the "content" of your condition:
if(randomBoolean)
console.log('this is executed');
console.log('this is always executed');
In that example if the randomBoolean variable is true the output will be:
this is executed
this is always executed
If the randomBoolean variable is false, you will see:
this is always executed

function toUpperArray(items) {
if (!items.length) return [] // end condition
var head = items[0] // item to operate
head = head.toUpperCase() // perform action
var tail = items.slice(1) // next
return [head].concat(toUpperArray(tail)) // recursive step
}
Line 1: If there are no items left in the array,
return an array with nothing in it.
Line 2: Take the first item of the given array
Line 3: transform it into upper-case letter
Line 4: create a new array without the just transformed item
Line 5: call the function with the remaining array, concat it with the transformed item and return.
What happens? lets take your example:
[ X, Y ] means, you have an array with array[0] = X, array[1] = Y. So you have items[0] = 'hello', items[1] = 'world'.
The first call is transforming 'hello' to 'HELLO'.
The remaining array is ['world'].
then the function gets called again and transforms it to 'WORLD'.
Then it is called again, has no items and then it returns an empty array. This means the second call can return too by concating ['WORLD'] with [].
Then the first call can return by concating ['HELLO'] with ['WORLD'] which is ['HELLO', 'WORLD'].

It converts all the values in the array up to UPPERCASE.
Could use for loop but they basically just call the function again for the next array value.

Related

Arrays and loops

I need some help with this, I'm stuck in JS Arrays & Loops, I don't know why this is telling me that if the function is empty is not returning "0".
function sumArray (numbers) {
// your code
var numbers = [1, 2, 3, 4];
if (numbers !== undefined) {
const sum = numbers.reduce((a,b) => a+b, 0)
return sum
}
else if ( numbers === []);{
return 0
}
}
sumArray();
I tried to return 0 when the array is empty, but I' don't know what I'm missig.
Beside the missing code, you could just return the result of reduce.
return numbers.reduce((a, b) => a + b, 0);
Some other annotations:
Do not redeclare and assign numbers, because you the the array as parameter.
Do not check against undefined here, because you get always an array as parameter.
You can not check an empty array with comparing another (literally) empty array, because arrays are objects and you compare different object references. For checking if an array is empty, take Array#length property and compare against zero.
The first issue is that you have a line ensuring that numbers is always an array containing 1,2,3,4; so the empty condition will never be met. So that line needs to be removed.
A second issue is that you have an extraneous semicolon that is subtly changing the logic.
The following logic will run the empty statement if numbers references the array object you just created using the array literal synax ([]); then a block will be evaluated outside of the else..if block, returning zero.
else if ( numbers === []);{
return 0
}
If you want to check if an object is an array you can use Array.isArray(foo).
If you want to check if an array is empty, you can test its length (if(myArray.length === 0) ...)
So what you probably meant to write was:
else if (numbers.length === 0) {
return 0
}
...but it turns out that the reduce code will work correctly if the array is of zero length; so that bit of logic is not necessary.
What you want is something like this:
function sumArray(numbers) {
if (!numbers) return 0;
return numbers.reduce((a,b) => a + b, 0);
}
console.log(sumArray())
console.log(sumArray([]))
console.log(sumArray([1, 2, 3, 4]))

Don't understand how this code can detect the length

var data = [1, 2, 3, 5, 2, 1, 4];
// iterate over elements and filter
var res = data.filter(function (v) {
// get the count of the current element in array
// and filter based on the count
return data.filter(function (v1) {
// compare with current element
return v1 == v;
// check length
}).length == 1;
});
console.log(res);
I understand all the line in this code, but I don't understand how it can detect the length==1.
(My opinion) Because it loop though every single element in the array and return boolean value either true or false so how it can use to detect the length?
This code is to get the array element that only appear once in the array.
The return true is not to return the boolean, but when you return true from inside a filter, that item gets added to the resulting array of filter function.
The process here is called chaining of methods. On line 11, first, the filter is applied to the data array, then the .length method is applied to the result of the filter, which will be an array of equal length or less than the number of elements in the data array. Then finally only once the return is called, which will be a boolean used for the outer filter.
Another example:
function reverseString (inputString) {
return inputString.split("").reverse().join()
}
In the above example, the function returns after the split, then reverse on the split's result, then join on the reverse's result. The final resulting string is only returned.
Don't think about it as lines of code. Split each segment of code into its true meaning my padawan
data.filter(function (v1) {
// compare with current element
return v1 == v;
// check length
})
filters the data array to return an array of elements from data such that every element in it is equal to v
By checking if its length is 1, you want to return true if the the array has only 1 element.
So,
var res = data.filter(function (v) {
// return true if there is only 1 element in data which is equal to v
});
Which basically means, we are filtering data, and returning a new array where every element is such that it has only one occurrence in the array.
The function for filter returns a boolean, but filter itself returns an array.
So, for example:
array.filter(function(element) { return element >= 0; });
says that the function function(element) { return element >= 0; } will be applied to each element in array. Then, if the result of the function is true, that element will exist in the final, filtered version of array (which is what the filter function returns), or will not exist if the result is false.
In effect, all negative numbers from array will be filtered out because they return false.
What your code is saying is the following: For every element in data, filter data to keep only the elements equal to the current one. If this filtered list has only one element, then it can only be our current element. Therefor this element exists only once and should be kept in the final result, so we return true if .length == 1. In the end, once this is done for every element, filter is smart enough to convert those results of true and false into an array of the elements that produced true and leave out those that produced a false.
I will describe the filter method step by step in detail.
First, it takes a condition. then it returns an array with all values which passed the condition successfully
so think about this block of code as a condition
return data.filter(function (v1) {
// compare with current element
return v1 == v;
// check length
}).length == 1;
so let's take the first part of the condition
data.filter(function (v1) {
// compare with current element
return v1 == v;
// check length
})
and let's say we gonna start with the first element 1 , so how many times v1 === v ? the answer is two times so it will return this array [1, 1]
so forget the condition we wrote in the first lines and think about it like that [1,1].length === 1.
So [1,1].length === 1 will return false
The same will happen with number 2. so let's talk about the number 3. it will be [3].length === 1 which is true which will go to the upper level and that's why the res will be finally [3, 5, 4]

Function call ending with [0][0]

var sensor = _this.createSensor("svg", mouse, "sensor_" + timestamp.substring(2, timestamp.length - 2))[0][0];
Can someone tell me what the [0][0] at the end of the function call is for?
Here is the header of my function :
DragSensorController.prototype.createSensor = function (parent, startPoint, id, ip, typeid, timestamp) {
It seems that:
_this.createSensor("svg", mouse, "sensor_" + timestamp.substring(2, timestamp.length - 2))
Returns an array of an array like:
[['foo']]
To access it, you need to use the [0][0].
const data = [['foo']];
console.log(data[0][0]);
The createSensor functions probably returns an array of arrays. For example:
[['item1', 'item2'], ['something1']]
So essentially it is selecting the first item from the first array. In this case item1
It means that the function returns an array and the first [0] obtains a reference to the first array element. Then, that element is, itself an array, so the second [0] gets the first element of that array.
function foo(){
var a = [[1,2,3], [4,5,6]];
// Calling this function will return an array consisting of two arrays
return a;
}
// Run the function and get the first item from the first array
console.log(foo()[0][0]); // 1
// Run the function and get the 3rd item from the second array
console.log(foo()[1][2]); // 6

Javascript/JQuery - Sort by split part of array?

I want to sort an array by a split part of an array.
example_array = ["Zebra:Add","Pay:Cold","And:Vets","Jam:Back"]
I want to so it sorts it like this:
console.log(code here) // prints ["Zebra:Add","Jam:Back","Pay:Cold","And:Vets"]
Note: I want "Zebra:Add","Pay:Cold", etc to stay together. I just want it be sorted by the text after the ":".
From your comment on the question:
I can't even think of a solution
Break the problem into smaller pieces. You want to sort an array by a part of the strings in the array, so you need to figure out / look into
How to sort an array (you've done that, you've found the sort method)
How to isolate the part of the string you want to sort on
How to correctly compare strings for Array#sort
How to do #2 and #3 within the context of doing #1
Re #2, there are various ways to do that. You could find the : via String#indexOf and then use substring to get all characters after it. You could split the string on :, then use the second half (if you know there won't be more than one : in the string). Or you could use a regular expression to isolate everything after the first :.
For instance, someString.match(/:.*$/)[0] isolates all characters starting with the first :. (Including the : is harmless, but you could use .substring(1) if you don't want to include it.)
Re #3: Array#sort expects its callback to return a negative number if the first argument should come before the second, 0 if their order doesn't matter, or a positive number if the second should come before the first. String#localeCompare compares strings according to the current locale and returns exactly that information, so we want to use that.
Re #4: Array#sort accepts a callback function, so you could do all the string splitting and comparison in that callback. But since the callback will be called repeatedly, frequently with either the first or second argument being one that's already been checked before, for larger arrays doing it then may be inefficient. It may make more sense to do all the string splitting / isolation in advance, then do the sort, then get your desired result.
So:
The not-particularly-efficient way (which is fine for data sets like your small array) is to isolate the part you want to sort on within the sort callback:
var array = ["Zebra:Add","Pay:Cold","And:Vets","Jam:Back"];
array.sort(function(left, right) {
return left.match(/:.*$/)[0].localeCompare(right.match(/:.*$/)[0]);
});
var array = ["Zebra:Add","Pay:Cold","And:Vets","Jam:Back"];
array.sort(function(left, right) {
return left.match(/:.*$/)[0].localeCompare(right.match(/:.*$/)[0]);
});
console.log(array);
With ES2015+ syntax:
const array = ["Zebra:Add","Pay:Cold","And:Vets","Jam:Back"];
array.sort((left, right) =>
left.match(/:.*$/)[0].localeCompare(right.match(/:.*$/)[0])
);
const array = ["Zebra:Add","Pay:Cold","And:Vets","Jam:Back"];
array.sort((left, right) =>
left.match(/:.*$/)[0].localeCompare(right.match(/:.*$/)[0])
);
console.log(array);
If it's a massive array where doing those splits on every compare is problematic, you could map first, then sort, then unmap:
var array = /*...really big array...*/;
array =
array.map(function(entry) { return {full: entry, key: entry.match(/:.*$/)[0]};})
.sort(function(left, right) { return left.key.localeCompare(right.key); })
.map(function(entry) { return entry.full; });
var array = ["Zebra:Add","Pay:Cold","And:Vets","Jam:Back"];
array =
array.map(function(entry) { return {full: entry, key: entry.match(/:.*$/)[0]};})
.sort(function(left, right) { return left.key.localeCompare(right.key); })
.map(function(entry) { return entry.full; });
console.log(array);
With ES2015+ syntax:
let array = /*...really big array...*/;
array =
array.map(entry => ({full: entry, key: entry.match(/:.*$/)[0] }))
.sort((left, right) => left.key.localeCompare(right.key))
.map(entry => entry.full);
let array = ["Zebra:Add","Pay:Cold","And:Vets","Jam:Back"];
array =
array.map(entry => ({full: entry, key: entry.match(/:.*$/)[0] }))
.sort((left, right) => left.key.localeCompare(right.key))
.map(entry => entry.full);
console.log(array);
I like the simplicity of the previous answer, in comparison My approach is probably too wordy! But here goes...
1.) take the original array and build a new sorting array from it, JSON array with each object having a text1 and text2 value... we'll sort on the text 2 value
2.) run a sort based on the text2 value
3.) empty the original array
4.) loop over the sorting array and re-populate the original array
heres a fiddle example I threw together
// STARTING ARRAY. WE WANT TO SORT BY THE TEXT AFTER THE COLON
example_array = ["Zebra:Add", "Pay:Cold", "And:Vets", "Jam:Back"];
// AN EMPTY ARRAY TO BUILD A JSON ARRAY FROM, THE SORT FROM THE DESIRED TEXT STRING
sorting_array = [];
// LOOP THROUGH THE ORIGINAL ARRAY AND PUSH A NEW OBJECT TO THE SORTING ARRAY
// EACH OBJECT CONTAINS A TEXT1 VALUE AND A TEXT2 VALUE
$.each(example_array, function(i, val){
sorting_array.push({"text1": val.split(':')[0], "text2": val.split(':')[1]})
})
// SORT THE SORTING ARRAY BY THE TEXT2 VALUE
sorting_array.sort(function(a, b){
if (a.text2 < b.text2) return -1;
if (b.text2 < a.text2) return 1;
return 0;
});
// EMPTY OUR ORIGINAL ARRAY
example_array = [];
// FOR DEMO PURPOSES LETS DISPLAY EACH IN THE DOM IN A UL ,
// AND ALSO RE-POPULATE THE ORIGINAL ARRAY WITHT HE NEW ORDER
$.each(sorting_array, function(i, val){
example_array.push(val.text1+':'+val.text2)
})
// TO SHOW THE NEW ORDER, LETS LOOP BACK OVER THE EXAMPLE_ARRAY
$.each(example_array, function(i, val){
$('ul').append('<li>' + val+ '</li>');
})

Removing duplicates from array ( understand the code)

I'm looking at an exercise and having trouble understand how the following works ( I'm trying to remove duplicates from an array)
var arr = ['a','b','c','a','b','d','e','f'];
var uniqueArray = arr.filter(function(item,pos){
return arr.indexOf(item) == pos;
});
My attempt to understand
Here item takes on all of our values in arr. Lets go through an iteration
First item = 'a' and pos = 0. Ok. now we want to only filter on the basis of if the index of 'a'is the same as 0
Here indexOf(a) == 0.
Great! this is true, lets put it in the new array.
Now lets move forward to where we see a again, namely at pos = 3
arr.indexOf(a) == 3
Wait... Doesent this meet our requirement as well? How does this even remove duplicates?
indexOf returns just one integer value, and it is the index of the first found item. So, when pos is 3 (and the item is a), indexOf will return 0 (because the first index of a is 0), 0==3 is false and the element will be removed.
Then, when the pos is 4 (and item is b), indexOf returns 2, the index of the first found b.
As for the objects, they can't have duplicate keys. Each new key will automatically overwrite the old one, so there won't be any duplicates.
Look:
var obj = {a:1, a:3, b:2,c:5,b:4};
console.log(obj)
nicael is right. indexOf(item) is just a function that goes through the array and looks for the first time item appears in the array, and returns the position in the array. In your example, if there is an a at 0 and a at index 3, then indexOf('a') will return position 0, while the value of pos is 3, so the filter returns false.
FOLLOW UP:
indexOf() has another parameter called the fromIndex, which lets you start the search from a position other than the beginning of the array. In this case, you can specify to skip over the first time 'a' occurs by doing arr.indexOf('a', 1) which starts the search at position 1, not 0. In this case the function would return true since the next 'a' is at position 3.
Can I use filter on an object?
No, because filter is a specific function of an Array object. You can get the keys of the object by doing a filter on Object.keys(myObject) since keys() returns an array.
Using your example:
var keyArray = Object.keys(myObject); //object can't have duplicate keys
keyArray.filter(function(item, index) {
return keyArray.indexOf(item) == index; //will never be false
});
Hashtable is the best way to eliminate the redundant values
Here is the code :
char arr[] = ['a','b','c','a','b','d','e','f'];
//it will contains all 26 places as zero (A - Z)
char hashArray[26]={0}
int i; //for iteration;
for(i=0;arr[i]!='\0';i++)
{
//it will subtracte the ascii value of the letter
//from 'a' so that we have the values from 0 to 26)
hashArray[arr[i]-'a']=arr[i];
}
for(i=0;i<26;i++)
{
if(hashArray[i]!=0) //to Ensure the positon has the character
{
printf("%c",hashArray[i]);
}
}

Categories