Khan Academy Towers of Hanoi recursion Step 3 - khan-academy

I need help on step three of solve Hanoi recursively and it says that all of my assertions do not pass and I have looked at other peoples answer and it is the same as mine. My code is Program.assertEqual(hanoi.isSolved("B"),true); that is what they say is wrong

Step 1:
var solveHanoi = function(numDisks, fromPeg, toPeg) {
if (numDisks===0){
return;
}
// recursive case:
};
You are meant to a case of 0 discs by writing the if statement in the function.
Step 2:
var solveHanoi = function(numDisks, fromPeg, toPeg) {
if (numDisks===0){
return;
}
// recursive case:
var sparePeg = hanoi.getSparePeg(fromPeg, toPeg);
solveHanoi(numDisks-1, fromPeg, sparePeg);
};
Now create a variable called 'sparePeg' then write in the function 'solveHanoi' 3 parameters like the code above.
Step 3:
var solveHanoi = function(numDisks, fromPeg, toPeg) {
if (numDisks===0){
return;
}
// recursive case:
var sparePeg = hanoi.getSparePeg(fromPeg, toPeg);
hanoi.moveDisk(fromPeg, toPeg);
solveHanoi(numDisks-1, fromPeg, sparePeg);
};
Now add the 'hanoi.moveDisk()' function with the parameters fromPeg and sparePeg.
Step 4 & 5:
var solveHanoi = function(numDisks, fromPeg, toPeg) {
if (numDisks===0){
return;
}
// recursive case:
else{
var sparePeg = hanoi.getSparePeg(fromPeg, toPeg);
solveHanoi(numDisks-1, fromPeg, sparePeg);
hanoi.moveDisk(fromPeg, toPeg);
solveHanoi(numDisks-1, sparePeg, toPeg);
}
};
solveHanoi(5, "A", "B");
Program.assertEqual(hanoi.isSolved("B"),true);
This is the easiest one. All you have to do is uncomment the last 2 lines of code.
Then you're finished!

Related

How to execute query async in sequelizer in NodeJs

hello i have try bellow code but my code not work properly
tags.forEach(function(value) {
var where1 = {};
var attr1 = ['id'];
attr1 = ['id'];
where1['name'] = value;
tagData['name'] = value;
tagModel.getTag(where1, attr1, function(code2,result2){
if(result2.length!=0) {
var quick_start_tagData={'quick_start_id' : result1['id'], 'tag_id' :result2[0]['id']}
quick_start_tagModel.saveData(quick_start_tagData, function(code2,result2){
});
console.log(quick_start_tagData);
} else {
tagModel.saveData(tagData, function(code2,result2) {});
}
});
});
problem is for loop iterate no.of data when i check value of that data into table if table have same value then get its id and insert and if not than add new record and get its id and insert into another table
but first select query execute all time and than insert query execute in loop
how to solve this issue
Query Execute like that way
Executing (default):
SELECT id FROM pxl_tag AS pxl_tag WHERE pxl_tag.name = 'a1';
SELECT id FROM pxl_tag AS pxl_tag WHERE pxl_tag.name = 'a2';
SELECT id FROM pxl_tag AS pxl_tag WHERE pxl_tag.name = 'a3';
INSERT INTO pxl_tag (id,name,created_at,updated_at) VALUES
(DEFAULT,'a3','2018-05-04 04:35:32','2018-05-04 04:35:32');
INSERT INTO pxl_tag (id,name,created_at,updated_at) VALUES
(DEFAULT,'a3','2018-05-04 04:35:32','2018-05-04 04:35:32');
INSERT INTO pxl_tag (id,name,created_at,updated_at) VALUES
(DEFAULT,'a3','2018-05-04 04:35:32','2018-05-04 04:35:32');
but i want first select and insert step by step
You can use each method from async library.
For example:
UPDATE
async.each(tags, function(value, cb) {
var where1 = {};
var attr1 = ['id'];
attr1 = ['id'];
where1['name'] = value;
tagData['name'] = value;
tagModel.getTag(where1, attr1, function(code2, result2) {
if (result2.length != 0) {
var quick_start_tagData = {
'quick_start_id': result1['id'],
'tag_id': result2[0]['id']
}
quick_start_tagModel.saveData(quick_start_tagData, function(code2, result2) {
cb();
});
console.log(quick_start_tagData);
} else {
tagModel.saveData(tagData, function(code2, result2) {
cb();
});
}
});
}, function(err) {
if (err) {
console.log('An error ocurred');
} else {
console.log('Nothing happens');
}
});
If I understood you correctly, the problem is not that your INSERTs doesn't run right after the SELECTs. Your problem is that you are calling async functions (getTag() and saveData()) inside a sync function loop (forEach()), thus, by the time that your async functions resolve, they get the last value for tagData which is defined inside the sync loop. You should give it a different scope to get the correct tagData value.
Try this (untested):
tags.forEach(function(value) {
var where1 = {};
var attr1 = ['id'];
attr1 = ['id'];
where1['name'] = value;
tagData['name'] = value;
saveTag(tagModel, quick_start_tagModel, where1, attr1, result1, tagData);
});
//Create a function so that tagData will have a different scope for each call
function saveTag(tagModel, quickStartTagModel, where, attr, result1, tagData) {
tagModel.getTag(where, attr, function(code,result){
if(result.length!=0) {
var quickStartTagData = {'quick_start_id' : result1['id'], 'tag_id' :result[0]['id']}
quickStartTagModel.saveData(quickStartTagData, function(code, result){});
console.log(quickStartTagData);
} else {
tagModel.saveData(tagData, function(code,result) {});
}
});
}
if you strictly need to run the SELECT and INSERT sequentially (and not async), you should look at promises and async library. This might help:
Resolve promises one after another (i.e. in sequence)?

Each month, populate spreadsheet data to next column [script needed]

I am developing a "Dashboard" [Sample Sheet Here] in which a number of data points are automatically calculated using formulas in Column C (NOTE: formulas not included in sample sheet).
I would like to create a monthly log of Column C data, in which cell values are copied to the next blank column of the corresponding Row
I have previously used the following script to log changes vertically, and could use a hand with repurposing for my desired outcome.
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Action Items" && r.getColumn() == 2 && r.getValue()) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Portion Tracking");
if(targetSheet.getLastRow() == targetSheet.getMaxRows()) {
targetSheet.insertRowAfter(targetSheet.getLastRow());
}
//Changes Start Here
var myRow = targetSheet.getLastRow()+1;
s.getRange(row, 1).copyTo(targetSheet.getRange(myRow,1));
s.getRange(row, 2).copyTo(targetSheet.getRange(myRow,2));
s.getRange(row, 3).copyTo(targetSheet.getRange(myRow,3));
}
}
AppendColumn()
I played around with this idea once and using a function I took from here and some of my own carving. I've comeup with an appendColumn() function.
Anyway it sounded like something you might want to have. You can take a look at it and in the meantime I'll take a look at your code.
function appendColumn(columnA)
{
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getValues();
var vB=transpose(vA);
sh.clear();
sh.getRange(1,1,vB.length,vB[0].length).setValues(vB);
sh.appendRow(columnA);
vD=sh.getDataRange().getValues();
sh.clear();
vE=transpose(vD);
sh.getRange(1,1,vE.length,vE[0].length).setValues(vE);;
}
function transpose(a)
{
return Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });
}
To test it I just called it like this.
function testAppendColumn()
{
appendColumn(['',1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]);
}
I'd like to see the source data. But assuming it has not changed then I'm guessing that this technique will work for you.
function onEdit(event)
{
var ss = event.source;
var s = event.source.getActiveSheet();
var r = event.range;
if(s.getName() == "Action Items" && r.getColumn() == 2 && r.getValue())
{
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Portion Tracking");
if(targetSheet.getLastRow() == targetSheet.getMaxRows())
{
targetSheet.insertRowAfter(targetSheet.getLastRow());
}
//Changes Start Here
var myCol = targetSheet.getLastColumn()+1;
s.getRange(row, 1).copyTo(targetSheet.getRange(1,myCol));
s.getRange(row, 2).copyTo(targetSheet.getRange(2,myCol));
s.getRange(row, 3).copyTo(targetSheet.getRange(3,myCol));
}
}
I don't understand the logic of connecting this to onEdit trigger but I'll assume that you do.

forEach using generators in Node.js

I'm using Koa.js framework and Mongoose.js module.
Normally to get a result from MongoDB I code like this:
var res = yield db.collection.findOne({id: 'my-id-here'}).exec();
But I need to execute this line for every element of an array named 'items'.
items.forEach(function(item) {
var res = yield db.collection.findOne({id: item.id}).exec();
console.log(res) // undefined
});
But this code doesn't run as yield is in the function. If I write this:
items.forEach(function *(item) {
var res = yield db.collection.findOne({id: item.id}).exec();
console.log(res) // undefined
});
I'm not getting the result in res variable either. I tried to use 'generator-foreach' module but that didn't worked like this.
I know that this is my lack of knowledge about the language literacy of Node.js. But can you guys help me finding a way how to do this?
You can yield arrays, so just map your async promises in another map
var fetchedItems = yield items.map((item) => {
return db.collection.findOne({id: item.id});
});
The accepted answer is wrong, there is no need to use a library, an array is already an iterable.
This is an old question, but since it has no correct answer yet and it appears on the first page on google search for the key terms "iterators and forEach" I will respond the question:
There is no need to iterate over an array, since an array already conforms to the iterable API.
inside your generator just use "yield* array" (note the * )
yield* expression is used to delegate to another generator or iterable object
Example:
let arr = [2, 3, 4];
function* g2() {
yield 1;
yield* arr;
yield 5;
}
var iterator = g2();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: 4, done: false }
console.log(iterator.next()); // { value: 5, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
For examples and in depth information visit:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield*
Thanks guys, I've done this using the 'CO' module. Thanks.
var co = require('co');
items.forEach(co(function* (item) {
var img = yield db.collection.findOne({id: item.id}).exec();
}));
EDIT: With the latest version of CO, you need co.wrap() for this to work.

Yii search with criteria and add parameters

I have one form and i want to search in my database. I create the object with all parameters but i have one problem. When write in one textfield search works fine and the query run correctly . When write two or more textfields params doesn't work and i have a fail execution of query :
WHERE
((((id_reservation=:id_reservation) AND (start=:start)) AND (end=:end)) AND
(fkCustomer.first_name=:first_name))
params doesn't replace.
$criteria=new CDbCriteria;
$criteria->with =array('fkCustomer');
if(!empty($start))
{
$criteria->addCondition('start=:start');
$criteria->params=array(':start'=>$start);
}
if(!empty($end))
{
$criteria->addCondition('end=:end');
$criteria->params=array(':end'=>$end);
}
if(!empty($merge->customer_name))
{
$criteria->addCondition('fkCustomer.first_name=:first_name');
$criteria->params=array(':first_name'=>$merge->customer_name);
}
if(!empty($merge->customer_surname))
{
$criteria->addCondition('fkCustomer.last_name=:last_name');
$criteria->params=array(':last_name'=>$merge->customer_surname);
}
if(!empty($merge->customer_email))
{
$criteria->addCondition('fkCustomer.email=:email');
$criteria->params=array(':email'=>$merge->customer_email);
}
$criteria->limit = 100;
It's because in every if block you replace the params array. Build an array in the if blocks then add it to $criteria->params on the last line, outside the blocks.
For instance:
$criteria=new CDbCriteria;
$criteria->with =array('fkCustomer');
$my_params = array();
if(!empty($end))
{
$criteria->addCondition('end=:end');
$my_params['end'] = $end;
}
if(!empty($merge->customer_name))
{
$criteria->addCondition('fkCustomer.first_name=:first_name');
$my_params['first_name'] = $merge->customer_name;
}
// other ifs ..
//then
$criteria->limit = 100;
$criteria->params = $my_params;
Also, if I remember correctly, you don't need to write ':end' and ':first_name' in the params array, it will work without the colon.
You also have the following alternative
$criteria=new CDbCriteria;
$criteria->with = 'fkCustomer';
if(!empty($end))
{
$criteria->compare('end', $end);
}
if(!empty($merge->customer_name))
{
$criteria->compare('fkCustomer.first_name', $merge->customer_name);
}
// The following conditions ..
// Limit:
$criteria->limit = 100;
Hi i think this is the same problem i have before with the params variable, for avoid this problem i use the CMap::mergeArray function
this happens because you overwrite the variable each time that the condition passed over it.
This is the syntax for avoid it, its an example
$criteria=new CDBCriteria;
$criteria->addBetweenCondition("Date",$datestart,$dateend);
$criteria->addCondition("Type=:type");
//$criteria->params=array(":type"=>"1"); //This is wrong, overwrites addBetweenCondition params
$criteria->params=CMap::mergeArray($criteria->params,array(
":type"=>"1",
)); //This is ok, mantain all parameters in the params var
$query=Model::findAll($criteria);
можно обратиться напрямую
$criteria=new CDbCriteria;
$criteria->with =array('fkCustomer');
if(!empty($start))
{
$criteria->addCondition('start=:start');
$criteria->params['start']=$start;
}
if(!empty($end))
{
$criteria->addCondition('end=:end');
$criteria->params['end']=$end;
}
if(!empty($merge->customer_name))
{
$criteria->addCondition('fkCustomer.first_name=:first_name');
$criteria->params['first_name']=$merge->customer_name;
}
if(!empty($merge->customer_surname))
{
$criteria->addCondition('fkCustomer.last_name=:last_name');
$criteria->params['last_name']=$merge->customer_surname;
}
if(!empty($merge->customer_email))
{
$criteria->addCondition('fkCustomer.email=:email');
$criteria->params['email']=$merge->customer_email;
}
$criteria->limit = 100;

How to snap a polyline to a road with walking travelmode in Google Maps?

II want an user to draw a route with polylines on GoogleMaps. I've found a way to snap a polyline ( example in the link, code in below ). The code works with the directions service to draw a polyline on a road, the only problem is this only works with G_TRAVELMODE_DRIVING but I want to use G_TRAVELMODE_WALKING and when you use WALKING you have to supply the map and a div in the constructor of the directions object. When I do that it automatically removes the last line and only displays the current line. I've tried several things like supplying the map as null, or leaving out the map in the constructor.. I've also tried to give a second map in the constructor, get the polylines from the directions service and display them on the right map. But nothing works! I'd appreciate it if someone could help me!
http://econym.org.uk/gmap/example_snappath.htm
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(53.7877, -2.9832),13)
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
var dirn = new GDirections();
var firstpoint = true;
var gmarkers = [];
var gpolys = [];
var dist = 0;
GEvent.addListener(map, "click", function(overlay,point) {
// == When the user clicks on a the map, get directiobns from that point to itself ==
if (!overlay) {
if (firstpoint) {
dirn.loadFromWaypoints([point.toUrlValue(6),point.toUrlValue(6)],{getPolyline:true});
} else {
dirn.loadFromWaypoints([gmarkers[gmarkers.length-1].getPoint(),point.toUrlValue(6)],{getPolyline:true});
}
}
});
// == when the load event completes, plot the point on the street ==
GEvent.addListener(dirn,"load", function() {
// snap to last vertex in the polyline
var n = dirn.getPolyline().getVertexCount();
var p=dirn.getPolyline().getVertex(n-1);
var marker=new GMarker(p);
map.addOverlay(marker);
// store the details
gmarkers.push(marker);
if (!firstpoint) {
map.addOverlay(dirn.getPolyline());
gpolys.push(dirn.getPolyline());
dist += dirn.getPolyline().Distance();
document.getElementById("distance").innerHTML="Path length: "+(dist/1000).toFixed(2)+" km. "+(dist/1609.344).toFixed(2)+" miles.";
}
firstpoint = false;
});
GEvent.addListener(dirn,"error", function() {
GLog.write("Failed: "+dirn.getStatus().code);
});
}
else {
alert("Sorry, the Google Maps API is not compatible with this browser");
}
I know it's an old post, but since no answer came forward and I've recently been working on this sort of code (and got it working), try swapping the addListener with this.
GEvent.addListener(map, "click", function(overlay,point) {
// == When the user clicks on a the map, get directiobns from that point to itself ==
if (!overlay) {
if (firstpoint) {
dirn1.loadFromWaypoints([point.toUrlValue(6),point.toUrlValue(6)],{ getPolyline:true,travelMode:G_TRAVEL_MODE_WALKING});
} else {
dirn1.loadFromWaypoints([gmarkers[gmarkers.length-1].getPoint(),point.toUrlValue(6)],{ getPolyline:true,travelMode:G_TRAVEL_MODE_WALKING});
}
}
});

Resources