Javascript - getElementID from scratch using BFS? - breadth-first-search

I'm trying to learn javascript, and spent tonight writing a getElementByID() function using Breadth-First Search. In short: I'm lost.
Fiddle: http://jsfiddle.net/timdown/a2Fm6/
Code:
var nodes = [];
function getElementById(node, id) {
alert(nodes.length);
if (node.childNodes[i].id == id) {
return node.childNodes[i];
} else if (node.childNodes[i].length > 0) {
for (var i = 0, len = node.childNodes.length; i < len; ++i) {
nodes.push(node.childNodes[i]);
}
}
if (nodes.length > 0) {
getElementById(nodes[0], id);
}
}
var el = getElementById(document.body, 'id');
Any help?

You're missing a for loop in the top half of your code. Where is i defined?
Here's how I'd write it:
function getElementById(node, id) {
//An array of all the nodes at the same depth
var nodes = [node];
//While the array is not empty
while(nodes.length) {
var newNodes = [];
for(var i = 0; i < nodes.length; i++) {
var children = nodes[i].childNodes;
for(var j = 0; j < children.length; j++) {
var child = children[j];
if(child.id == id) {
return child
}
newNodes.push(child);
}
}
//Replace nodes with an array of the nodes the next level down
nodes = newNodes
}
}

Related

Why in console even numbers gives empty list?

void main() {
List<int> numbers = [55,58,62,15,14,19,20];
List oddNumbers = [];
List evenNumbers = [];
for (int index = 0; index < numbers.length; index++) {
print(numbers[index]);
if(numbers[index]% 2 !=0) {
oddNumbers.add(numbers[index]);
} else if(numbers[index]%2 != 0) {
evenNumbers.add(numbers[index]);
}
}
print("Odd numbers:$oddNumbers");
print("Even numbers:$evenNumbers");
}
it gives:
Odd numbers:[55, 15, 19]
Even numbers:[]
Why the even numbers list is empty?
Hi You're using same logic in both if and else conditions. Please check below snippet.
if(numbers[index]% 2 !=0) {
oddNumbers.add(numbers[index]); } else
if(numbers[index]%2 == 0) {
evenNumbers.add(numbers[index]); } }
for (int index = 0; index < numbers.length; index++) {
if(numbers[index]% 2 !=0) {
oddNumbers.add(numbers[index]);
} else if(numbers[index]% 2 != 1) {
evenNumbers.add(numbers[index]);
}
}
print("Odd numbers:$oddNumbers");
print("Even numbers:$evenNumbers");

Dart: Class members seem to be wrong when access from a separate class

Anyone know if this is a Dart bug or is it my misunderstanding of how Dart coding works?
I am learning Dart to investigate feasibility of eventually using Flutter; however, while exploring the language, I found a weird behavior (maybe a bug). I tried repro'ing it by writing a similar pattern of code, but have yet to figure out what causes it. In the attached code, I wrote a quicksort class. In that class, it counts the number of times the "sort" method is recursed and saves the count in a class member called "recurseCount".
From the main() class, if I use the QuickSort class directly, I have no issue getting back the recurseCount member; however, if I call it from a different class (called "Tester"), I do not get the correct value for "recurseCount". Why would calling a class from a separate class cause members to not provide the correct values?
import 'package:test/test.dart';
import 'dart:math' as _math;
// ***********************
enum SortOrder { ascending, descending, unsorted }
class QuickSort {
List list = [];
SortOrder sortOrder = SortOrder.unsorted;
int recurseCount = 0;
QuickSort({this.list}) {
if (list != null && list.length > 1) {
list = sort(useRandomPivot: true);
}
}
List sort(
{List iList,
int leftIndex = 0,
int rightIndex,
bool useRandomPivot = true}) {
if (iList != null) list = iList;
if (list.isEmpty) return [];
rightIndex ??= list.length - 1;
if (rightIndex > list.length - 1) rightIndex = list.length - 1;
if (leftIndex < rightIndex) {
recurseCount++;
var partitionIndex =
_partition(leftIndex, rightIndex, useRandomPivot: useRandomPivot);
if (partitionIndex == -1) {
//already sorted List
if (sortOrder == SortOrder.ascending) {
return list;
} else {
//SortOrder.descending
list = list.reversed.toList(); // Time Complexity of O(n)
sortOrder = SortOrder.ascending;
return list;
}
} else {
sort(leftIndex: leftIndex, rightIndex: partitionIndex - 1);
sort(leftIndex: partitionIndex + 1, rightIndex: rightIndex);
}
} else {
sortOrder = SortOrder.ascending;
}
return list;
}
int _partition(int leftIndex, int rightIndex, {bool useRandomPivot = true}) {
// in case the array is already sorted from the start; only run through the partition'ing one time
// note: regardless of ascending or descending order
if (leftIndex == 0 && rightIndex >= list.length - 1) {
sortOrder = checkSorting(list);
if (sortOrder != SortOrder.unsorted) {
return -1;
}
if (useRandomPivot) {
var random = _math.Random();
var randomIndex = random.nextInt(rightIndex - leftIndex);
_swapElements(randomIndex, rightIndex);
}
}
int pivotVal = list[rightIndex]; //select the last item as the pivot
var headIndex = leftIndex - 1;
for (var scanIndex = leftIndex; scanIndex < rightIndex; scanIndex++) {
if (list[scanIndex] <= pivotVal) {
headIndex++;
_swapElements(headIndex, scanIndex);
}
}
var partitionIndex = headIndex + 1;
_swapElements(partitionIndex, rightIndex);
return partitionIndex;
}
void _swapElements(position1, position2) {
int tempVal = list[position1];
list[position1] = list[position2];
list[position2] = tempVal;
}
SortOrder checkSorting(List arr) {
var isAsc = true;
var isDesc = true;
for (var i = 0; i < arr.length - 1; i++) {
if (arr[i] < arr[i + 1]) isDesc = false;
if (arr[i] > arr[i + 1]) isAsc = false;
if (!isDesc && !isAsc) break; // not sorted Asc or Desc
}
if (isAsc) {
return SortOrder.ascending;
} else if (isDesc) return SortOrder.descending;
return SortOrder.unsorted;
}
}
// ***********************TESTS*********************************
num log2(num n) => _math.log(n) / _math.ln2;
List getRandomIntList({int min = 0, int max = 10000, int len}) {
var random = _math.Random();
var tempList = List(len);
for (var i = 0; i < len; i++) {
tempList[i] = random.nextInt(max - min);
}
return tempList;
}
class Tester {
static num _runControlTest(List list) {
var stopwatch = Stopwatch();
stopwatch.start();
list.sort();
stopwatch.stop();
return stopwatch.elapsedMicroseconds;
}
static void runTests(List list, String groupName,
{bool useRandomPivot = false, bool sortFromConstructor = false}) {
// CONTROL
var controlElapsedTimeMicroSec = 0;
controlElapsedTimeMicroSec = _runControlTest(list);
// END CONTROL
var expectedRecursionCountLogN = log2(list.length).ceil();
var expectedRecursionCountNLogN = list.length * expectedRecursionCountLogN;
var qs = QuickSort();
var stopwatch = Stopwatch();
stopwatch.start();
list =
qs.sort(iList: list, useRandomPivot: useRandomPivot); // METHOD TO TEST
stopwatch.stop();
var elapsedTimeMicroSec = stopwatch.elapsedMicroseconds;
var recursionCount = qs
.recurseCount; //NOTE (BUG in Dart?): unable to get the recurseCount correctly from within this class/method
group(groupName, () {
var testSubject =
'Time Taken: ${controlElapsedTimeMicroSec} microseconds';
var reason =
'The built in sort took ${controlElapsedTimeMicroSec} microseconds, while the test took ${elapsedTimeMicroSec}.';
test(testSubject, () {
expect(
elapsedTimeMicroSec, lessThanOrEqualTo(controlElapsedTimeMicroSec),
reason: reason);
});
testSubject =
'Time Complexity: ${recursionCount} vs ${expectedRecursionCountNLogN}';
reason =
'Time Complexity of ${recursionCount} is greater than either range (LogN) ${expectedRecursionCountLogN} or (N*LogN) ${expectedRecursionCountNLogN}';
test(testSubject, () {
expect(recursionCount, lessThanOrEqualTo(expectedRecursionCountNLogN),
reason: reason);
});
});
}
}
void main() {
var min = 0;
var len = 1000000;
var max = len;
var originalList = getRandomIntList(min: min, max: max, len: len);
var list = List.from(originalList);
// BUG? When called within this Tester.runTests the sort method does NOT return the correct recurseCount
Tester.runTests(list, 'UNSORTED_RIGHT_PIVOT', useRandomPivot: false);
list = List.from(originalList);
var qs = QuickSort();
// When called directly from main() the sort method DOES return the correct recurseCount
var stopwatch = Stopwatch()..start();
qs.sort(iList: list, useRandomPivot: true); //METHOD TO TEST
stopwatch.stop();
group('UNSORTED_RANDOM_PIVOT', () {
test('Time Taken: ${stopwatch.elapsedMicroseconds} microseconds', () {
expect(stopwatch.elapsedMicroseconds,
lessThanOrEqualTo(Tester._runControlTest(originalList)));
});
var nLogN = (list.length * (log2(list.length).ceil()));
test('Time Complexity: ${qs.recurseCount} vs $nLogN', () {
expect(qs.recurseCount, lessThanOrEqualTo(nLogN));
});
});
}

More than 100 points and one polyline, Google Maps v3

I'm working with google maps api v3 and I'm trying to use snap to road with more than 100 points but in addition end up with just one polyline with the whole route that I can put a small animation. The view is a html.erb.
var apiKey = any_key;
var map = handler.getMap();
var drawingManager;
var placeIdArray = [];
var snappedCoordinates = [];
var path = <%= raw(#locations) %>
var markers = <%= raw(#markers) %>
var centerOn = path[0].split(',');
function breadCrumbsGrapher(path) {
handler.removeMarkers(Gmaps.store.markers);
for(var i = 0; i < polylines.length; i++) {
polylines[i].setMap(null);
}
var divided = handlePath(path);
if (typeof divided[0] == 'object') {
for(var i = 0; i < divided.length; i++) {
runSnapToRoad(divided[i]);
}
} else {
runSnapToRoad(path);
}
}
function waypointsLimiter(path) {
var path_loc_size = path.length;
var limited = [];
if(path_loc_size > 30) {
var stepper = Math.ceil(path_loc_size/30);
for(var i = stepper; i < path_loc_size; i += stepper) {
limited.push(path[i]);
}
if(limited.indexOf(path[path_loc_size-1]) == -1) {
limited.push(path[path_loc_size-1]);
}
} else {
limited = path;
}
return limited;
}
function handlePath(path) {
var i = 0;
var j = path.length;
if (j > 100) {
var newArray = [],
chunk = j/2;
if (j >= 200) {
chunk = j/3;
} else if (j >= 300) {
chunk = j/4;
} else if (j >= 400) {
chunk = j/5;
} else if (j >= 500 ) {
chunk = j/6;
} else if (j >= 600) {
chunk = j/7;
} else if (j >= 700 || j <= 799) {
chunk = j/8;
} else {
alert('La ruta no puede ser mostrada');
}
for (i, j; i < j; i+=chunk) {
newArray.push(path.slice(i,i+chunk+1));
}
return newArray;
} else {
return path;
}
}
// Snap a user-created polyline to roads and draw the snapped path
function runSnapToRoad(path) {
var path = path.join('|');
$.get('https://roads.googleapis.com/v1/snapToRoads', {
interpolate: true,
key: apiKey,
path: path,
}, function(data) {
processSnapToRoadResponse(data);
drawSnappedPolyline();
});
}
// Store snapped polyline returned by the snap-to-road service.
function processSnapToRoadResponse(data) {
snappedCoordinates = [];
placeIdArray = [];
for (var i = 0; i < data.snappedPoints.length; i++) {
var latlng = new google.maps.LatLng(
data.snappedPoints[i].location.latitude,
data.snappedPoints[i].location.longitude);
snappedCoordinates.push(latlng);
placeIdArray.push(data.snappedPoints[i].placeId);
}
}
// Draws the snapped polyline (after processing snap-to-road response).
function drawSnappedPolyline() {
var symbol = {
path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
scale: 3,
strokeColor: '#3B16B3'
};
var snappedPolyline = new google.maps.Polyline({
path: snappedCoordinates,
strokeColor: '#E51E25',
strokeWeight: 3,
icons: [{
icon: symbol,
offset: '0%'
}]
});
snappedPolyline.setMap(map);
animate(snappedPolyline);
zoomToObject(snappedPolyline);
polylines.push(snappedPolyline);
}
function zoomToObject(obj){
var bounds = new google.maps.LatLngBounds();
var points = obj.getPath().getArray();
for (var n = 0; n < points.length ; n++){
bounds.extend(points[n]);
}
map.fitBounds(bounds);
}
function animate(line) {
var count = 0;
window.setInterval(function() {
count = (count + 1) % 600;
var icons = line.get('icons');
icons[0].offset = (count / 6) + '%';
line.set('icons', icons);
}, 70);
}
breadCrumbsGrapher(path);
Also I've tried declaring a variable outside so I can concat all of the coordinates and generate a polyline with it but doesn't seem to work. Actualy that big array ends up being of 2000+ points.
The result that I have with the provided code
After all of that the issue is that I don't know how to merge the polylines to have just one line and being able to animate just that one line. If there's more than 100 coordinates I plot more polylines. In the image you can see that there's 3 icons (one for each polyline) and I need just to draw one line and have 1 icon.
To reproduce the issue just add a key and if you want use this set of coordinates:
https://drive.google.com/file/d/1jLb7Djv5DiSdR3k4QZRSatXBwrohlxcI/view?usp=sharing
function breadCrumbsGrapher(path) {
//mapMarkers();
snappedCoordinates = [];
handler.removeMarkers(Gmaps.store.markers);
for(var i = 0; i < polylines.length; i++) {
polylines[i].setMap(null);
}
var divided = handlePath(path);
if (typeof divided[0] == 'object') {
for(var i = 0; i < divided.length; i++) {
runSnapToRoad(divided[i]);
}
} else {
runSnapToRoad(path);
}
console.log(snappedCoordinates);
drawSnappedPolyline();
}
function runSnapToRoad(path) {
var path = path.join('|');
$.get('https://roads.googleapis.com/v1/snapToRoads', {
interpolate: true,
key: apiKey,
path: path,
}, function(data) {
processSnapToRoadResponse(data);
//drawSnappedPolyline();
});
}
I've changed the code but it doesn't work, even though I end up with a 2,557 coordinates array.
I've tried also tried this thinking that this could give me the time to have all coordinates:
async function breadCrumbsGrapher(path) {
//mapMarkers();
snappedCoordinates = [];
handler.removeMarkers(Gmaps.store.markers);
for(var i = 0; i < polylines.length; i++) {
polylines[i].setMap(null);
}
var divided = handlePath(path);
if (typeof divided[0] == 'object') {
for(var i = 0; i < divided.length; i++) {
await runSnapToRoad(divided[i]);
}
} else {
await runSnapToRoad(path);
}
console.log(snappedCoordinates);
drawSnappedPolyline();
}
and:
async function runSnapToRoad(path) {
var path = path.join('|');
await $.get('https://roads.googleapis.com/v1/snapToRoads', {
interpolate: true,
key: apiKey,
path: path,
}, function(data) {
processSnapToRoadResponse(data);
});
}
Thank you in advance.
You are using $.get() to query the Roads API which is an asynchronous call so when you call drawSnappedPolyline() from within your breadCrumbsGrapher function, you most probably don't (yet) have all coordinates in return from your AJAX call(s).
If you have 550 coordinates in your original path, you then know you must call the Roads API 6 times (5 times with 100 points + 1 time with 50 points). You should then be able to set a counter somewhere, to only draw your (complete) Polyline, once you got your 6 responses from the Roads API.
Or you could base that on the length of your final array (compared to the original path) although I don't know what would happen in case some points can't be "snapped".

Kendo UI Datasource onRequestEnd e.response.Data not found

i'm trying to intercept datetime value in kendo datasource to adjust UTC time offset but i can't find the e.response.Data property
code
var interceptDate = []; // List of intercept member
var onRequestEnd = function (e) {
setIntercept(e); // another function to fill interceptDate from schema
if (e.response.Data && e.response.Data.length) {
var rowsData = e.response.Data;
if (interceptDate.length > 0) {
if (this.group().length && e.type == "read") {
for (var i = 0; i < rowsData.length; i++) {
var gr = rowsData[i];
for (var j = 0; j < interceptDate.length; j++) {
if (gr.Member == interceptDate[j]) {
gr.Key = gr.Key.replace(/\d+/,
function (n) { return parseInt(n) + offsetMiliseconds; }
);
}
addOffset(gr.Items);
}
}
} else {
addOffset(rowsData);
}
}
}
};
in chrome devtools the e.response look like
_defaultPrevented: false
isDefaultPrevented: function (){return this._defaultPrevented===!0}
preventDefault: function (){this._defaultPrevented=!0}
response: Object
odata.count: "4"
odata.metadata: "http://localhost:7000/odata/$metadata#DateIntercept"
value: Array[4]
0: Object
1: Object
2: Object
3: Object
length: 4
__proto__: Array[0]
__proto__: Object
sender: lt.extend.init
type: "read"
__proto__: Object
If you want to modify the returned data, you should use the parse callback in the dataSource's schema. Leaving out irrelevant stuff it would look something like:
new kendo.ui.Grid({
dataSource: new kendo.data.DataSource({
schema: {
parse: function (results) {
for (var i = 0; i < results.length; i++) {
// MODIFY RESULTS HERE. FOR EXAMPLE
results[i].someField = results[i].someField + " Hello World";
}
return results;
}
}
});
});

MVC Survey and capturing data

Im kinda new to MVC and have built a site with a risk calculator.
This all works fine the site works for users logging in and the form calculates the form then sends the user to the correct page.
When a user signs in with account and fills out the survey i want to capture the score on the database but cannot work out how/where to do this. Should i be writing the code in the behind file for the survey form?
here is the script
<script type="text/javascript">
function test_it(entry) {
if (entry.value != null && entry.value.length != 0) {
entry.value = "" + eval(entry.value);
}
computeForm(entry.form);
}
function computeForm(form) {
var total = 0
for (var count = 0; count < 5; count++) {
if (form.a[count].checked) {
var total = total + parseInt(form.a[count].value);
}
}
for (var count = 0; count < 5; count++) {
if (form.b[count].checked) {
var total = total + parseInt(form.b[count].value);
}
}
for (var count = 0; count < 5; count++) {
if (form.c[count].checked) {
var total = total + parseInt(form.c[count].value);
}
}
for (var count = 0; count < 5; count++) {
if (form.d[count].checked) {
var total = total + parseInt(form.d[count].value);
}
}
for (var count = 0; count < 5; count++) {
if (form.e[count].checked) {
var total = total + parseInt(form.e[count].value);
}
}
for (var count = 0; count < 5; count++) {
if (form.f[count].checked) {
var total = total + parseInt(form.f[count].value);
}
}
for (var count = 0; count < 5; count++) {
if (form.g[count].checked) {
var total = total + parseInt(form.g[count].value);
}
}
for (var count = 0; count < 5; count++) {
if (form.h[count].checked) {
var total = total + parseInt(form.h[count].value);
}
}
for (var count = 0; count < 5; count++) {
if (form.i[count].checked) {
var total = total + parseInt(form.i[count].value);
}
}
for (var count = 0; count < 5; count++) {
if (form.j[count].checked) {
var total = total + parseInt(form.j[count].value);
}
}
for (var count = 0; count < 5; count++) {
if (form.k[count].checked) {
var total = total + parseInt(form.k[count].value);
}
}
for (var count = 0; count < 5; count++) {
if (form.l[count].checked) {
var total = total + parseInt(form.l[count].value);
}
}
if (total <= 5) { window.location = "End_Page_1" }
else if (total <= 12) { window.location = "End_Page_2" }
else if (total <= 24) { window.location = "End_Page_3" }
else if (total <= 30) { window.location = "End_Page_4" }
else if (total <= 48) { window.location = "End_Page_5" }
}
</script>
Any ideas how i could do this would be much appreciated.
Andy
Suppose you have a Model
public class Calculator
{
public string Field1 {get;set;}
public string Field2 {get;set;}
public string Field3 {get;set;}
...
}
write a controller which would just send a empty model to the view. Like
public ActionResult FillSurvey()
{
Calculator calci = new Calculator();
return View(calci);
}
now right click this action and choose add view here choose strongly typed view. Choose your Model Calculator and also choose scffold template. choose create. A new View will be generated where in you can enter values and write one more method/Action in controller.Like
[HTTPPOST]
public ActionResult FillSurvey(Calculator calci)
{
//do whatever you want here. You will have all the values entered in UI
//captured in this method
}

Resources