When does the call stack get set up in Javascript? - javascript

In trying to solve the following problem:
Generate all combinations of an array of string.
Ex: Input: ['A', 'T', 'C', 'K']
Output: [
'ATCK', 'ATC', 'ATK',
'AT', 'ACK', 'AC',
'AK', 'A', 'TCK',
'TC', 'TK', 'T',
'CK', 'C', 'K',
''
]
I have the following code:
function getSpellableWords(arr) {
const res = [];
// helper(arr, res, 0, '');
helper(arr, res, 0, []);
return res;
}
function helper(arr, res, i, slate) {
const char = arr[i];
console.log(i, 'i')
if(i === arr.length) {
res.push(slate.join(''));
return;
}
// slate = slate + char;
slate.push(char)
console.log(slate, 'slate')
helper(arr, res, i+1, slate);
slate.pop()
helper(arr, res, i+1, slate);
}
getSpellableWords(['A', 'T', 'C', 'K']);
My questions is:
If I remove the following lines in the code:
helper(arr, res, i+1, slate);
Once i is equal to 5 (which is the array.length), the code will stop after it pushes slate into res. However, if I leave that line in, a call stack is set up and so i will go up from 1->5, then pop out gradually to 4 then 3 then back to 4 and so on. Why does that happen?
Clarification: So I understand that for each recursion call, another i variable is generated. However, I was expecting the second recursion call to also generate i from 1->4 again, but this time instead of incrementing it linearly, there's backtracking going on as well. Why wasn't there backtracking in the first call, and why does the second call generate the rest of the results when the first call only generates the first result?

Each recursive call of helper will indeed add a level on the call stack, so that when a recursive call returns back to its caller, that calling code can continue with its own local execution context.
Each execution of helper has its own execution context, which includes a local variable i which is only visible to that execution context. It only plays a role at that level in the call stack.
Note that the helper code never changes the value of its i variable. It gets initialised with whatever value is passed as third argument when it gets called, and that is the only value it will ever have.
The change to i that you notice is in fact no change. Every different value you see for i is in fact about a different variable that just happens to have the same name.
Here is a little schema on the life of these i variables for when the res variable has length 2 (just to not make it too lengthy!):
helper(arr, res, 0, []); // The initial call
+--------top level helper execution context----+
| i = 0 |
| .... |
| slate.push(char) |
| helper(arr, res, i+1, slate); |
| +---nested helper execution context---+ |
| | i = 1 | |
| | .... | |
| | slate.push(char) | |
| | helper(arr, res, i+1, slate); | |
| | +--deepest exec. context-----+ | |
| | | i = 2 | | |
| | | ... | | |
| | | res.push(slate.join('')); | | |
| | | return; | | |
| | +----------------------------+ | |
| | // i is still 1 | |
| | slate.pop() | |
| | helper(arr, res, i+1, slate); | |
| | +----------------------------+ | |
| | | i = 2 | | |
| | | ... | | |
| | | res.push(slate.join('')); | | |
| | | return; | | |
| | +----------------------------+ | |
| | // i is still 1 | |
| +-------------------------------------+ |
| // i is still 0 |
| slate.pop() |
| helper(arr, res, i+1, slate); |
| +-------------------------------------+ |
| | i = 1 | |
| | .... | |
| | slate.push(char) | |
| | helper(arr, res, i+1, slate); | |
| | +----------------------------+ | |
| | | i = 2 | | |
| | | ... | | |
| | | res.push(slate.join('')); | | |
| | | return; | | |
| | +----------------------------+ | |
| | // i is still 1 | |
| | slate.pop() | |
| | helper(arr, res, i+1, slate); | |
| | +----------------------------+ | |
| | | i = 2 | | |
| | | ... | | |
| | | res.push(slate.join('')); | | |
| | | return; | | |
| | +----------------------------+ | |
| | // i is still 1 | |
| +-------------------------------------+ |
| // i is still 0 |
+----------------------------------------------+
So we see that, in this particular algorithm, the size of the call stack (i.e. the depth of the recursion tree) corresponds exactly to the value of the variable i in the current execution context. When a function returns, the size of the call stack is reduced (i.e. the recursion depth decreased), and so we arrive in a state (popped from the stack) where there is another instance of i that also has a value that matches the now current size of the call stack.

Trincot gave a helpful detailed response on how that function works internally. I'd just like to point out a significant simplification you could write:
const getSpellableWords = ([x, ...xs]) =>
x == undefined
? ['']
: ((ps = getSpellableWords (xs)) => [...ps .map (p => x + p), ...ps]) ()
console .log (
getSpellableWords (['A', 'T', 'C', 'K'])
)
.as-console-wrapper {max-height: 100% !important; top: 0}
Here we note that the words we can make either include the first character or they don't. We can recursively calculate all the words from the remainder and then return the result of combining that array of words with those ones found by prepending the first character to each. And of course our recursion bottoms out if there are no characters left, in which our array returned contains only the empty string.
There is a slight bit of syntactic trickery here, with an IIFE in the recursive branch. We might prefer to use a call helper function, which takes a function and any arguments and calls that function with those arguments. Sometimes that's clearer:
const call = (fn, ...args) => fn (...args)
const getSpellableWords = ([x, ...xs]) =>
x == undefined
? ['']
: call (
(ps) => [...ps .map (p => x + p), ...ps],
getSpellableWords (xs)
)

Related

Dexiejs - Filtering returns single value

My dexiedb structure looks like below.
const db = new Dexie('shipment-execution');
db.version(1).stores({
root: '++id,shipmentid,stopid',
})
My IndexedDB will look like below
| id| shipmentid| stopid|
| 1 | 6000001 | 10 |
| 2 | 6000001 | 20 |
| 3 | 6000001 | 30 |
| 4 | 6000002 | 10 |
| 5 | 6000002 | 20 |
I am trying to get all the data which has shipmentid equal to 6000001. Each time it is returning only one record (the first record ).
db.root.where({shipmentid : '6000001'}).toArray().then((d)=>{
console.log(d);
})
output is only fetching the first record
| id| shipmentid| stopid|
| 1| 6000001 | 10 |
Please let me know, what I am doing wrong.

Graphs and adjacency list practice

Hey guys so I am currently work on a problem involving graphs and adjacency lists but it is not working. This is for self-study only and it is not for school or homework.
I am given this table of values:
| Start name | End name | Example path found by a search |
|------------|----------|-----------------------------------|
| carrie | carrie | carrie (it's the same node) |
| carrie | humza | carrie -> humza |
| carrie | yervand | carrie -> jun -> silla -> yervand |
| ophelia | ursula | ophelia -> travis -> **FAIL** |
| travis | carrie | travis -> ophelia -> **FAIL** |
| ursula | ophelia | ursula -> travis -> ophelia |
| victor | humza | victor -> **FAIL** |
But my code is just not working it is saying that I am not getting this:
from carrie to carrie
from carrie to humza
And I am doing it with breath-first as recommended by them and Idk what the issue is
if (!adjacencyList[startName]) return null;
const queue = [startName];
let visited = new Set();
let currentVertex;
if (adjacencyList[startName] === adjacencyList[endName]) return adjacencyList[startName]
while(queue.length) {
currentVertex = queue.shift();
if (!visited.has(currentVertex)) {
visited.add(currentVertex);
adjacencyList[currentVertex].forEach(neighbor => queue.push(neighbor))
}
}
if (visited.has(endName)) {
return visited;
}
else {
return null
}
}
Idk what the issue is and how to fix it. I thought that by returning the set I would return the path but apparently not.

Restrict Find and Replace function using map() to single column in a 2d array JavaScript

I am working in Google sheets
I have a find and replace function gotten from here. It works great when the array is made from a single column of data
But, in certain instances in which I want to use my function I have all my data sitting in an array which is being passed from prior processing, the data if printed to the page looks like
| Id | Segment |Other Column| etc..
|----|--------------------|------------|
| 1 | AAA AA|AA|CaaL AA |stuff |
| 2 | AAA-AA|AA|CaaL |stuff |
| 3 | AAA, AA|AA|AA |AA |
| 4 | AA |stuff |
| 5 | AA AA | |
| 6 | AA, AA |AA |
| 7 | |stuff |
| 8 | CaaL |stuff |
| 9 | AA |stuff |
I only want to replace data in the Segment column
| Id | Segment ||Other Column| etc..
|----|-------------------|------------|
| 1 | AAA AA|zz|CaaL AA |stuff |
| 2 | AAA-AA|zz|Bob |stuff |
| 3 | AAA, AA|zz|zz |AA |
| 4 | zz |stuff |
| 5 | AA AA | |
| 6 | AA, AA |AA |
| 7 | |stuff |
| 8 | Bob |stuff |
| 9 | zz |stuff |
As it is the AA in the Other Column (could be in any column, I have no way of knowing) is being replaced which I do not want
Can the findReplace function be restricted to a single column in values updating that only that column in values ?
I have tried getting the column array I want to restrict values to with
function getColumn(matrix, col, startrow){
var column = [];
for(var i=startrow; i<matrix.length; i++){
column.push(matrix[i][col]);
}
return column;
}
and then attempting to restrict the input to this column
function fr(input) {
const aCOL = getColumn(values,2,0)
return input.aCOL.map(c => c.replace(regex, (x) => map[x]));
AND
return input.map(c => c.aCOL.map(y => y.replace(regex, (x) => map[x])));
}
I get Cannot read property 'map' of undefined
Thanks
function findReplace(values) {
var search_for = ["AA", "Caal"];
var replace_with = ["zz", "yy"];
var map = {};
search_for.forEach(function(item, i) {
map[item] = replace_with[i];
});
//map = { AA: 'zz', Caal: 'yy' };
const regex = new RegExp("(?<![^|])(?:" + search_for.join("|") + ")(?![^|])", "g");
range.setValues(values.map(fr));
function fr(input) {
return input.map(c => c.replace(regex, (x) => map[x]));
}
}
The code you got from your previous question works fine if you just change the range you're retrieving. So instead of creating a function to extract the column into an array, you can just adjust the range.
If the column you want to replace ('Segment') is the second one, then you can do the following changes.
From:
const col = ss.getRange(2, 3, ss.getLastRow()).getValues();
...
ss.getRange(2, 3, ss.getLastRow()).setValues(col.map(fr));
To:
const col = ss.getRange(2, 2, ss.getLastRow()).getValues();
...
ss.getRange(2, 2, ss.getLastRow()).setValues(col.map(fr));

Is it possible to sort things by categorized columns in isotope?

I'd like to sort things in a format similar to the following...
-----------------------
| cat1 | dog1 | bird1 |
-----------------------
| cat2 | dog2 | bird2 |
-----------------------
| cat3 | dog3 |
---------------
| dog4 |
--------
Is it possible to sort this way?
I understand it's possible to do a linear column sort similar to this:
----------------------
| cat1 | cat4 | cat7 |
----------------------
| cat2 | cat5 | cat8 |
----------------------
| cat3 | cat6 |
---------------
But I need it to sort by category. Is it possible to do this in isotope and if so can you provide an example?
Also can it sort in two (or more) different ways simultaneously like this?
(Notice the cats are sorted vertically while the dogs are sorted horizontally.)
----------------------
| cat1 | cat4 | cat7 |
----------------------
| cat2 | cat5 | cat8 |
----------------------
| cat3 | cat6 |
----------------------
| dog1 | dog2 | dog3 |
----------------------
| dog4 | dog5 | dog6 |
----------------------
| dog7 |
--------
Unfortunately Isotop doesn't supoort your requests by current version (v2.1.0) but You can add Null element ( like a empty div with height and width ) in the categories and show / hide them according by your needs for example for displaying this order
-----------------------
| cat1 | dog1 | bird1 |
-----------------------
| cat2 | dog2 | bird2 |
-----------------------
| cat3 | dog3 |
---------------
| dog4 |
--------
you can add a null element and show at last row of items as below and choose cellsByColumn for its layout. Null elements doesn't have anything in content and style . They only fill spaces by their height / width.
-----------------------
| cat1 | dog1 | bird1 |
-----------------------
| cat2 | dog2 | bird2 |
-----------------------
| cat3 | dog3 |
---------------
| Null | dog4 |
---------------
for achieving another structure, you can add another Null element at third column's point and choose normal layout.
----------------------
| cat1 | cat4 | cat7 |
----------------------
| cat2 | cat5 | cat8 |
----------------------
| cat3 | cat6 | Null |
----------------------
| dog1 | dog2 | dog3 |
----------------------
| dog4 | dog5 | dog6 |
----------------------
| dog7 |
--------
Check out my codes for sample1 and sample2.
for this kind of similar requirement
i have used this
function sortBy(tag) {
$('.isotope-item').each(function(index, value)
{
var arrayOfCategories = $(this).attr('data-category').split(" ");
for (var i=0; i < arrayOfCategories.length; i++){
if((tag.indexOf(arrayOfCategories[i]) !== -1)) {
//console.log('match');
$(this).attr('data-sort-order', 1);
break;
} else {
//console.log('no match');
$(this).attr('data-sort-order', 2);
}
}
});
$container.isotope( 'updateSortData', $('.isotope-item'));
//$container.isotope( 'reLayout' );
$container.isotope({ sortBy : 'sortOrder' });
}
and i am setting "data-sort-order" attribute for some category items, By passing the "data-sort-order" value to the function will sort the elements which has this properties.

How to parse data from a mysql tracking db?

I have a working event tracker that writes every event in a mysql table.
Table
id date userid event
5100 2014-03-25 14:18:55 user333 AI
5101 2014-03-25 14:19:02 user333 Click
5102 2014-03-25 14:19:02 user333 Click
...
Thats works so far very good. But now, I want to write a little report tool in node.js
I try to get the values with this SQL Query:
SELECT DATE_FORMAT(date,"%Y%m%d") AS date, event, count(*) AS count FROM databasetest WHERE date>="'+ daystartdate +'" AND date<="'+ dayenddate +'" GROUP BY YEAR(date), MONTH(date), DAY(date), event
Giving me this:
+----------+----------+-------+
| date | event | count |
+----------+----------+-------+
| 20140320 | AI | 6 |
| 20140320 | Click | 2 |
| 20140320 | swipe | 2 |
| 20140321 | Click | 6 |
| 20140321 | error | 5 |
| 20140321 | swipe | 2 |
| 20140321 | touch | 3 |
| 20140322 | AI | 3 |
| 20140322 | Click | 3 |
| 20140322 | error | 1 |
| 20140322 | mapsload | 3 |
| 20140322 | touch | 1 |
| 20140323 | AI | 2 |
| 20140323 | Click | 2 |
| 20140323 | touch | 5 |
| 20140324 | AI | 3 |
| 20140324 | Click | 1 |
| 20140325 | AI | 25 |
| 20140325 | Click | 48 |
| 20140325 | error | 16 |
| 20140325 | mapsload | 7 |
| 20140325 | swipe | 15 |
| 20140325 | touch | 32 |
+----------+----------+-------+
But I need the data in this form:
+----------+----------+-------+-----
| date | Click | AI | ....
+----------+----------+-------+-----
| 20140320 | 0 | 6 |
| 20140321 | 2 | 2 |
| 20140321 | 2 | 5 |
Is this possible with a SQL query or do I need to loop through the results in my javascript code. I tried many possible solution but didnt get it to work.
Thank you.
This is a very common question, keywords to search are "transpose" and "pivot". To save you the trouble, this is something that MySQL is not able to do. SQL Server (a MS product) can do this, though.
You will need to loop through the output and build the result set yourself.
var results = []
data.forEach(function(row, rowidx) {
results[row.date] = results[row.date] || {};
results[row.date][row.event] = results[row.date][row.event] || 0;
results[row.date][row.event] += row.count;
});

Categories

Resources