Function call ending with [0][0] - javascript

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

Related

Why Do I need to pass an Object to Array.from?

I don't understand why the followings provide different results, and on the second one I see people using an underscore (_, i), but I am not really sure what it does.
let test1 = Array.from(5, (v,i) => i); //empty array;
let test2 = Array.from({length:5}, (v,i) => i); // [0,1,2,3,4]
I don't get why I need to pass an object to get an array populated of the first n numbers.
Could someone please explain?
Let's see the signature of Array.from() method first.
Array.from(arrayLike, mapFn)
So, the first argument should be an arrayLike object (an object that has a length property of a non-negative integer). You can pass an array, string, etc. as well.
The second parameter is a map function which maps the the elements of the first argument (arrayLike) to the returned value from the callback function.
This map function takes a callback function with following signature.
callback(value, index)
The map function creates a new array populated with the results of calling the callback function (v, i) => i on every element in first argument of Array.from.
Now, let's see first case,
let test1 = Array.from(5, (v,i) => i);
Here, (v, i) => i is a map function. v is element of arrayLike object and i is the index of that element. The index i is returned.
But, 5 is neither an array nor an arrayLike object and the length property of 5 is undefined. So, map function maps no (zero) element and produces an empty array. Think of the following implementation.
function mapFn (arrayLike, callback) {
let result = [];
for (let i = 0; i < arrayLike.length; i++) {
let mappedValue = callback(arrayLike[i], i);
result.push(mappedValue);
}
return result;
}
If you pass 5 to the mapFn function, the for loop iterates 0 times and mapFn returns an empty array.
In case of second example,
let test2 = Array.from({length:5}, (v,i) => i); // [0,1,2,3,4]
{length: 5} is an arrayLike object. The map function produces an array with returned values of the callback function. The callback function returns index. Hence, [0,1,2,3,4].
In the callback function only the i parameter is used and returned from the function. v argument is not used. But, it needs to be there so that the second parameter i can be accessed. So, (_, i) is same as (v, i). You can name the parameters with any valid variable name.
You are basically following the following approach
Array.from(arrayLike, (currentValue, index) => { ... } )
So the arrayLike variable needs to be either a string, map ... or it should be an object determining the length of the array (like in your case). So in your case the size of the array is determined by the arrayLike object. currentvalue is undefined every time the arrow function runs and the index goes from 0 to arrayLike.length - 1.
Because it is expecting and arrayLike object and arrays have a length property.

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>');
})

What gets passed to the .map() iterator function on an array?

I have a function that takes in an array of objects and a string, which represents a property. The function should return an array containing that property from each object.
Here is my sample code:
function pluck(array, property) {
var newArr = [];
array.map(function(paints){
return newArr.push(paints[property]);
});
return newArr;
}
This returns a new array and it works. But when the function is taking in an array of objects as one of the arguments...what gets passed to the anonymous iterator function in the map method? The value of the key?
How would it iterate over an array of objects using the map method?
The comments on your question explain what is happening in your code.
When you call map on an array, the mapping function is provided with 3 arguments, which are used always, sometimes and rarely in that order.
const result = items.map(function(element, index, items) {
// do the mapping
});
The function is called for each element of the original array items in turn, and the result of the function placed in the same index position of the result array.
The function arguments are:
element - this is the current element from the array
index - the current index
items - the original array on which map was called
Your pluck function could be written as:
function pluck(arr, prop) {
return arr.map(item => item[prop]);
}

Array Map callback function with only one argument returns the callback function argument as index instead of the item itself

I don't know why this is happening but in an array where i am running the map function, the callback function of maps get its first argument as the index number instead of the item. If I assign two arguments then it's working like how it should work i.e first arg as index and second arg as item but when i assign only one argument it gives me index number instead of the item itself.
Below is my function block:
return companies_det.map(function (company_det) {
console.log(company_det);
var $ = cheerio.load(company_det);
var company_name = $(company_det).find('a').text(),
company_esomar_url = $(company_det).find('a').attr('href');
return Rq(company_esomar_url)
.then(function (web_data) {
var $ = cheerio.load(web_data);
return {
company_name: company_name,
company_url: $('a[data-ga-category="website"]').attr('href')
}
})
.catch(function (err) {
return err;
})
});
In the above function, If I do console.log(company_det) I receive index number instead of the companies_det array items.
That is not possible if companies_det is an Array of objects and map is Array.map.
You have not provided the code with the actual problem. Either you stored the array indices in companies_det, or companies_det is not an array and it is not the standard map function.
Try logging companies_det.

How does this recursive function end?

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.

Categories