find the least value in a array in angularjs - javascript

I'm trying to show the nearest branch location in a map.SO i want to get the branch which has the least difference between the current location and the branch location. i have taken the differenec like this.
for(var i=0;i<$scope.locations.BranchAndAtms.length;i++){
var mapObject = $scope.locations.BranchAndAtms[i];
var differenceLat = (mapObject.lat - c.latitude);
var differenceLon = (mapObject.lon - c.longitude);
var Difference = (differenceLat + differenceLon);
alert(Difference );
Now i get the difference between every branch in my array.how to take the value with the least difference.
NOTE: difference i get comes in minus as well as positive values.

Outside of your for loop, you'll want to declare a variable that is going to keep track of which array index has the lowest value and another for what the lowest value currently is. By default, it will store the very first item as the lowest - this comes in handy if there is only one item in your array.
var lowest_index = 0;
var lowest_value = 0;
Inside of your for loop, you'll want to take the absolute values of the differences.
for...
var differenceLat = Math.abs(mapObject.lat - c.latitude);
var differenceLon = Math.abs(mapObject.lon - c .longitude);
Now, compare the existing lowest value to the current one, and if the current is lower, set lowest to that value of i.
if(Difference < lowest_value) {
lowest_index = i;
lowest_value = Difference;
}
So, your code should look like:
var lowest_index = 0;
var lowest_value = 0;
for(var i=0;i<$scope.locations.BranchAndAtms.length;i++){
var mapObject = $scope.locations.BranchAndAtms[i];
var differenceLat = Math.abs(mapObject.lat - c.latitude);
var differenceLon = Math.abs(mapObject.lon - c.longitude);
var Difference = (differenceLat + differenceLon);
if(Difference < lowest_value) {
lowest_index = i;
lowest_value = Difference;
}
}

In addition to Steve's answer, I'd recommend taking a look at how to correctly calculate distances between locations: Calculate distance between two latitude-longitude points? (Haversine formula)
So, create a function for calculating the distance:
function calculateDistance(currentLocation, branchLocation) {
/* the actual implementation, use answers from
* https://stackoverflow.com/questions/27928/ as reference
*
* Note that if you want, you could also use the actual latitude
* and longitude values as parameters for this function:
* calculateDistance(currentLat, currentLon, branchLat, branchLon)
*/
return distance;
}
And then use it inside the for-loop instead of the current difference calculations:
var Difference = calculateDistance(c, mapObject);
// or if you want to have the separate latitude and longitude parameters:
// var Difference = calculateDistance(c.latitude, c.longitude, mapObject.lat, mapObject.lon);
Otherwise Steve's approach is valid to follow.
(If you'd like to show for example all branch locations within given distance, or all the nearest branch locations if there are more than one branch with exactly the same distance, you'll need to store the distances and sort by them. But this goes out of the topic, as you did want to show only one branch location.)

Related

Demanding multiple coordinates from an undefined amount of elements

Firstly I would like to give you an example, of what exactly I am talking about, and afterwards what I found out/different problems.
I would like to ask for every element, here points (they do share a class) with a diameter of 1 px. To simplify it, I thought of putting it inside an array. The amount of these points is undefined, there may be 2 or 100.
Afterwards i would like to store the x and y coordinates, which I get with the getBoundingClientRect() function, inside a new array. In which I would use every first for x and every second for y.
Now do not confuse this with the position within the array, I would like to know how I can "convert" the element from a query so I can use the getBoundingClientRect() function.
I hope this is all the information needed. I myself researched on here, but I could not find anything that was near my (rather big) demand.
I do not have any code, which I think would be useful.
I have found a solution myself. It is definitely not the smoothest nor the fastest solution, but it works.
for(iAllPoints=0;iAllPoints<(aPoints-1);iAllPoints++)
{
//Creating necesarry variables and asking for the needed data from CSS
var sPointPos = document.querySelector(".startPoint").getBoundingClientRect();
var tarPoints = document.querySelector(".target");
var AOfTarPoints = document.getElementsByClassName("target").length;
var calculatedDistances = [];
//Demanding all coordinates from each target point. Aswel as calculating the distance
if (iAllPoints!=(aPoints-2))
{
for(i = 0;i<AOfTarPoints;i++)
{
tarPoints = document.querySelector(".target");
//Calculating
var SideA = sPointPos.top - tarPoints.getBoundingClientRect().top;
var SideB = sPointPos.left - tarPoints.getBoundingClientRect().left;
var CEPDistance = Math.sqrt(Math.pow(SideA,2)+Math.pow(SideB,2));
calculatedDistances[i] = CEPDistance;
tarPoints.classList.add("inCalculation");
tarPoints.classList.remove("target");
}
minimum = Math.min.apply(Math,calculatedDistances);
var smallestDistance = document.querySelector(".inCalculation");
document.querySelector(".startPoint").classList.add("used");
document.querySelector(".startPoint").classList.remove("startPoint");
smallestDistance.classList.add("startPoint");
smallestDistance.classList.remove("inCalculation");
//Reseting the left unused points for next point
document.querySelector(".inCalculation").classList.add("target");
document.querySelector(".inCalculation").classList.remove("inCalculation");
finalDistance += minimum;
}
else
{
for(i = 0;i<AOfTarPoints;i++)
{
tarPoints = document.querySelector(".target");
//Calculating
var SideA = sPointPos.top - tarPoints.getBoundingClientRect().top;
var SideB = sPointPos.left - tarPoints.getBoundingClientRect().left;
var CEPDistance = Math.sqrt(Math.pow(SideA,2)+Math.pow(SideB,2));
calculatedDistances[i] = CEPDistance;
tarPoints.classList.add("inCalculation");
tarPoints.classList.remove("target");
}
minimum = Math.min.apply(Math,calculatedDistances);
var smallestDistance = document.querySelector(".inCalculation");
document.querySelector(".startPoint").classList.add("used");
document.querySelector(".startPoint").classList.remove("startPoint");
smallestDistance.classList.add("used");
smallestDistance.classList.remove("inCalculation");
finalDistance += minimum;
}
I haven't given every single Variable, but you should be able to understand it either way.

Dynamic variable declaration. Is this even the right method?

A little new to JS so be gentle :)
I'm trying to create a program that holds 5000+ boolean values that dynamically change based on other vars.
const chars = "abcdefghijklmnopqrstuvwxyz0";
const charsC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0"
const maxNum = 48;
const maxTile = 6;
var tile1, tile2, tile3, tile4, tile5, tile6
// test vars
var tile4 = "A27"
var t4a27 = false
// this snippet will be in an interval loop
for (let i = 1; i <= maxTile; ++i) {
for (let n = 0; n < chars.length; ++n) {
for (let j = 1; j <= maxNum; ++j) {
// this obviously doesnt work
var t[i][`${chars[n]}`][j];
// ^ ^ ^
if (tile[i] == `${charsC[n]}${j}`) {
t[i][h][j] = true;
console.log(t4a27)
} else {
t[i][h][j] = false;
}
}
}
}
For clarification a better word than "tile" for the vars could be "sprite" rather because its a point on the sprite.
The basic concept is the tile vars are designed to output their current position as a string value e.g. "A27". Then this loop will take that information and scan each tile subset to be true/false. So if the sprite lower right quadrant is inside "A27" the output would be t4a27 = true
In practice I can do this with just a lot of code (over 20,000 lines) but I figured their has to be an easier way that requires far less code.
This is probably not the right approach for your problem.
If you really need to store this amount of variables, it is probably best to put them in an object like so:
var tiles = {}
var tileName = 'abc'
// Dynamic setting:
tile[tileName] = true
// Dynamic reading:
console.log(tile[tileName])
I am wondering if you really want to store 5000 variables or if there is another way to calculate them at the time you need time, but that requires a bit more knowledge of the problem.
Javascript doesn't have this kind of ability to reflect local variables.
What you can do is attach all those variables to a global object, and proceed with: Object.keys(your_object) and your_object[key_name_here] = ...
I think you should use a 2-dim array for this. Or use a regular array of booleans with the appropriate size and do the index-magic yourself.
As you said, you are running on coordinates. A-27 is the same as row(1)+field(27) -- considering A is 1
If your field is 500x100, you create an Array as such: let gamefield = Array(500*100);
Warning: I have not tested this for syntax errors, but you should get the idea.
let gamefield = Array(500*100);
// optional gamefield.fill(true);
let row = idx => idx * 500;
let posIdx = (r, c) => row(r) + c;
// there is a sprite with a tiles property that returns
// 4 index positions for the sprite's quadrants as [r,c]
let quadrants = sprite.tiles.reportPositions()
// filter the quadrants where the gamefield at r,c is true
// this might also be a good case for some() instead of filter()
let collisions = quadrants.filter(pos => return gamefield[posIdx(...pos)]);
// if there is any of these, you can kill the sprite.
if(collisions.length > 0) sprite.kill();

How do i simplify a block of code that ParseInt Retrieves from localstorage variables

I have this game which i am designing where i store 1 or 0 values as correct or incorrect answers in the local storage in variables q1 - q6.
Since local storage doesnt store numbers as integers, before my main page loads i parseInt all of my variables to get the integers. Although some of them havent been declared as anything yet so they seem to be NaN or null, so when i try to compute the addition of all of the variables, it gives me NaN unless i use this mess of a code.
if (isNaN(totalpoints)) totalpoints = 0;
if (localStorage.getItem("points") === null){
localStorage.setItem("points", "0");
}
var q0 = parseInt(localStorage.q0);
var q1 = parseInt(localStorage.q1);
var q2 = parseInt(localStorage.q2);
var q3 = parseInt(localStorage.q3);
var q4 = parseInt(localStorage.q4);
var q5 = parseInt(localStorage.q5);
var q6 = parseInt(localStorage.q6);
if (isNaN(q0))q0=0;
if (isNaN(q1))q1=0;
if (isNaN(q2))q2=0;
if (isNaN(q3))q3=0;
if (isNaN(q4))q4=0;
if (isNaN(q5))q5=0;
if (isNaN(q6))q6=0;
var totalpoints = totalpoints + q0 + q1 + q2 + q3 + q4 + q5 + q6;
localStorage.setItem("points", totalpoints);
I am trying to think of a way where i can simplify this code into maybe a few lines using a loop for the variables possibly or something?
Can anyone give me any sense of direction on how i can approach this or help me possibly?
Im just not sure as it seems like i got to parseInt the localstorage variables all individually?
Thanks
Rather than having multiple separate numeric-indexed properties, consider using a single array instead:
const qArr = localStorage.qArr
? JSON.parse(localStorage.qArr)
: new Array(7).fill(0);
Then, instead of assigning to the q variables, assign to an index of the qArr, and to save it, use JSON.stringify:
qArr[3] = 555;
localStorage.qArr = JSON.stringify(qArr);
To add up all the items in the array, you can use reduce:
totalPoints = qArr.reduce((a, b) => a + b, totalPoints);
Since it sounds like this is all in one self-contained script, I'd highly recommend consolidating all the relevant items that need to be stored into a single object too, if at all possible, so as not to pollute localStorage with lots of separate properties that really deserve to be in a single place, rather than spread out, eg:
const dataObj = localStorage.pointsData
? JSON.parse(pointsData)
: {
totalPoints: 0,
qArr: new Array(7).fill(0)
};
Then, do stuff with dataObj.totalPoints and dataObj.qArr, and when you need to save it, do something like:
localStorage.pointsData = JSON.stringify(dataObj);
I would suggest an object.
You can store object as answers in localStorage and update the values.
So suppose answers object is something like this
answers = {
q0: 10,
q2: 20
}
Then it won't matter whether key is present or not, as you can loop through object to get total sum
let total = 0;
for (const key in answers) {
total += answers[key];
}
Of course you have to store that object in localStorage like this
localStorage.setItem('answers', JSON.stringify(answers));
And while getting you have to parse it
const answers = JSON.parse(localStorage.getItem('answers'));
I suggest to replace multiple values with one single array.
So, your saving function could be something like this:
function savePoint(point) {
var points = JSON.parse(localStorage.points || "[]");
points.push(point);
localStorage.points = JSON.stringify(points);
}
And you will calculate the total like this:
function calculateTotal() {
var points = JSON.parse(localStorage.points || "[]");
return points.reduce(function(total, point) {
return total + point;
}, 0);
}
Anyway, I suggest to think about a data model to store the points and using JSON.stringify + JSON.parse to store it in localStorage.
Since you have points q0 - q7 plus the points, there are 8 variables. Now, if we carefully go through your code, things that are common
You fetch a variable from a local storage
You convert it to integer
You check whether it is NaN. If NaN, you set to 0.
Finally, you use the variable to calculate the sum
Okay. So we will try to write a function that does steps 1-3 with
function oneForAll(variableName){
if (localStorage.getItem(variableName) === null){
localStorage.setItem(variableName, "0");
}
var variable = parseInt(localStorage.getItem(variableName));
if (isNaN(variable)) {
variable = 0;
}
return variable
}
I basically used most of your lines so that you can relate to it.
Now, for step 4, we need to use our function to get the total sum. Also, we need a loop.
var listOfVariables = ["points", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7" ]
var totalPoints = 0;
// loop over the list of variables
listOfVariables.forEach(variableName => {
totalPoints += oneForAll(variableName);
});
// finally you set the new calculated total points
localStorage.setItem("points", totalpoints);
Hope this is helpful.

Picking random values from array and creating new array

I have an array, and need to pick three random values from that array. These will the be put in a new array and I will be able to see the new array on my website. I also have to make sure that no value gets picked twice.
This is what I have so far:
var student = ["Hans","Ole","Nils","Olav","Per","Knut","Line","Pia"];
var velg = student[Math.floor(Math.random() * student.length)];
I'm thinking I should add an id to my HTML, so the new array will show on my website, but I'm not sure about the rest.
First sort it randomly and then get first three:
student
.sort(function(){
return Math.random() - 0.5;
})
.slice(0,3)
Since Math.random() returns random value between 0 and 1, while sort expects values to be positive or negative to determine order we, we need to subtract 0.5 to make those negatives possible.
You could try something like this in a loop
var students = ["Hans","Ole","Nils","Olav","Per","Knut","Line","Pia"];
var randomStudents = [];
for(var i = 0; i < 3; i++) {
var velg = student[Math.floor(Math.random() * students.length)];
randomStudents.push(velg);
}
Note that this can add duplicate students to the array. You should check if student is already in the array and try again.
Keyword for that would be recursion.
https://www.codecademy.com/courses/javascript-lesson-205/0/1

How do I sum the values from an array, one by one, until the total is larger than x?

I have this JS to get the widths of a bunch of sibling elements and add those widths to an array.
var nav = document.querySelector('.js-primary-nav');
var childrenWidths = [];
for(var i=0; i<nav.childElementCount; i++){
childrenWidths.push(nav.children[i].offsetWidth);
}
Now I want to cycle through these widths, adding them up until the total is greater than X (which will be the container width). I then want to get the positions of the values up until the one which tipped the total over into larger than X so I can add those values to one pile and the others to another.
How do I cycle through the values, adding and then comparing the total to a number?
Thanks
You need to define X, but it's a simple loop.
Iterate the nodeList, add the current offsetWidth to the variable tracking, make sure to define the max so you can pass the condition.
When current > max, run whatever code you need to and escape the loop.
var max = [number];
var current = 0;
[].forEach.call(document.querySelector('.js-primary-nav'), function(x) {
current += x.offsetWidth;
if (current >= max) {
//do something
return;
}
});

Categories