0

I'm having trouble figuring out on how can I properly use the array of distance that I made. I am creating a simple web app where user is going to select their origin and preferred destination and I need to compute for the ETA. I already can compute for ETA but the code is so long and so I was wondering if there is better way to do this. for example: 1) in the select options I have 4 locations which is manila,QC, makati and marikina. 2) if the user selected Manila as Origin and QC as the destination I can compute it using only if-else but if I were to consider every possible way my code will be long with if-else statement.

BTW this is just a sample data of select options and the true data consist of 24 locations and destinations. So I'm really hoping I can have an easy way to do this.

I only tried if-else statement and I was thinking maybe I just loop it but I don't how to start. please see code for reference. Thank you!

console.clear()
function validateSelect(e) {
  var origin = e.target.querySelector("[name=origin]").value;
  var destination = e.target.querySelector("[name=destination]").value;
  if (origin == destination) {
    e.stopPropagation()
    e.preventDefault()
    alert("Origin and Destination can't be the same");
    return false;
  }
}

var distanceArray = [10000,20000,30000];
//manila to qc 10000 meter
//qc to makati 20000 meter
//makati to marikina 30000 meter
document.getElementById('findEta').addEventListener('submit', validateSelect);//for form find eta
function getEta(){
    var selectedOrigin = document.getElementById("origin").selectedIndex;
    var selectedDestination = document.getElementById("destination").selectedIndex;
    var estimatedTimeOfArrival = document.getElementById("estimatedTimeOfArrival");


  if((selectedOrigin ==  0)&& (selectedDestination == 1)){
        //manila to qc
        distance = 10000;
        var speed = 5.56; //converted speed from 20km/h
        time = distance/speed; 
        eta = Math.floor(time).toString();
        if((eta >=60)){
            var newEta = eta /60; //minutes
            var mod = eta%60; //seconds
            newEta = Math.floor(newEta);
            estimatedTimeOfArrival.value = newEta + "m "+mod+"s" ;
        }else{
            eta.toString();
            estimatedTimeOfArrival.value = eta + " s";
        }
    }else if((selectedOrigin ==  0)&& (selectedDestination == 2)){

        distance = 20000;
        var speed = 5.56;
        time = distance/speed; 
        eta = Math.floor(time).toString();
        if((eta >=60)){
            var newEta = eta /60; //minutes
            var mod = eta%60; //seconds
            newEta = Math.floor(newEta);
            estimatedTimeOfArrival.value = newEta + "m "+mod+"s" ;
        }else{
            eta.toString();
            estimatedTimeOfArrival.value = eta + " s";
        }
    }else if((selectedOrigin ==  0)&& (selectedDestination == 2)){
        distance = 30000;

        var speed = 5.56;
        time = distance/speed; 
        eta = Math.floor(time).toString();
        if((eta >=60)){
            var newEta = eta /60; //minutes
            var mod = eta%60; //seconds
            newEta = Math.floor(newEta);
            estimatedTimeOfArrival.value = newEta + "m "+mod+"s" ;
        }else{
            eta.toString();
            estimatedTimeOfArrival.value = eta + " s";
        }
    }
}
function alertFunction(){
    var selectedOrigin = document.getElementById("origin").value;
    var selectedDestination = document.getElementById("destination").value;
    var estimatedTimeOfArrival = document.getElementById("estimatedTimeOfArrival");
if((selectedOrigin == "")&&(selectedDestination =="")){
    alert("Please select an option first.");
}else if(selectedOrigin == selectedDestination){
    validateSelect(e);
}
else{
    getEta();
    alert("\nYour Origin is: "+selectedOrigin+"\nYour Destination is: "+selectedDestination+"\nYour ETA is: "+estimatedTimeOfArrival.value);
}
    
}
<form action="" id="findEta">
        <select name="origin" id="origin">
            <option value="manila">manila</option>
            <option value="QC">QC</option>
            <option value="makati">Makati</option>
            <option value="marikina">marikina</option>
        </select>
        <select name="destination" id="destination">
            <option value="manila">manila</option>
            <option value="QC">QC</option>
            <option value="makati">Makati</option>
            <option value="marikina">marikina</option>
        </select>
        <input type="hidden" name="estimatedTimeOfArrival"id="estimatedTimeOfArrival">
        <button type="submit" value="submit" onclick="alertFunction()">submit</button>
    </form>

2
  • What is the distance if selectedOrigin is 1 and selectedDestination is 2? Commented May 14, 2019 at 4:09
  • @VLAZ It should be 20000 meter, I see that the second else if should be else if((selectedOrigin == 1)&& (selectedDestination == 2)){ Commented May 14, 2019 at 4:15

4 Answers 4

2

We can rule out travel from point A to point A (0 distance) and we can assume that the trip from point A to point B is the same distance as the reverse trip. With this, representing places as single letters (a, b, c, d) a matrix of distances can be described compactly like this... (with made-up distance values)

let distances = {
  ab: 1000,
  ac: 2000,
  ad: 3000,
  bc: 1500,
  bd: 2500,
  cd: 1200
}

function distance(from, to) {
  let key = [from, to].sort().join('')
  return distances[key]
}

console.log(distance('d', 'a'))
console.log(distance('b', 'c'))

Sign up to request clarification or add additional context in comments.

2 Comments

Really neat solution. A typo though: I think the element dc should really be cd. As is, console.log(distance('c','d')) yields undefined.
Good catch @chatnoir. Thanks!
1

If my understanding is correct, your ETA calculation is the same for each, the variables are the origin and destination which together give you the distance.

To simplify your logic, what you can do is store your distances indexed by these in an object or multi-dimensional array e.g.:

const distances = {
  0: {
    1: 10000,
    2: 20000
  },
  ...
}

And then just lookup the distance from there, e.g.:

const distance = distances[selectedOrigin][selectedDestination];
const speed = 5.56;
...

To take this one step further, you could make it easier to read your structure by using the name values directly in your object, e.g.:

const distances = {
  manila: {
    qc: 10000,
    makati: 20000
  },
  ...
}

And then use the values during lookup, e.g.:

const selectedOrigin = document.getElementById("origin").value;
const selectedDestination = document.getElementById("destination").value;
const distance = distances[selectedOrigin][selectedDestination];
const speed = 5.56;
...

2 Comments

Thank you I understand it now, do you have any references where I can read more about this object or multi-dimentional array?
@indefinite Happy to help, Mozilla has some good documentation - you can find more information about multi-dimensional arrays here (along with JS array details) and objects here
1

I would consider holding all information in a JSON object or similar.

You can then dynamically populate the drop downs based on the object, including dynamically populating the destination drop down based on origin.

As we are populating the destination dynamically based on origin, we can save the lookup by putting the distance directly as the value of the destination options

//Object to hold info
//Adjust distances as required
const origins = {
  "manila": {
    "name": "Manilla",
    "distances": {
      "QC": 1000,
      "makati": 2000,
      "marikina": 3000
    }
  },
  "QC": {
    "name": "QC",
    "distances": {
      "manila": 1000,
      "makati": 2000,
      "marikina": 3000
    }
  },
  "makati": {
    "name": "Makati",
    "distances": {
      "manila": 2000,
      "QC": 2000,
      "marikina": 3000
    }
  },
  "marikina": {
    "name": "Marikina",
    "distances": {
      "manila": 3000,
      "QC": 3000,
      "makati": 3000
    }
  }
}


let originDD = document.getElementById("origin");
let destinationDD = document.getElementById("destination");

originDD.innerHTML = "<option value=''>Please Select</option>"

//Populate Origins
for (var prop in origins) {
  originDD.innerHTML += `<option value=${prop}>${origins[prop].name}</option>`;
}

//Populate Destinations on change
originDD.addEventListener("change", function() {
  var thisOrigin = this.value;
  destinationDD.innerHTML = "<option value=''>Please Select</option>";
  for (var dest in origins[thisOrigin].distances) {
    console.log(dest);
    console.log(origins[dest])
    destinationDD.innerHTML += `<option value=${origins[thisOrigin].distances[dest]}>${origins[dest].name}</option>`
  }
});

//Calculate on destination change
destinationDD.addEventListener("change", function() {
      var distance = parseInt(this.value, 10);
      var speed = 5.56; //converted speed from 20km/h
      var time = distance / speed;
      var eta = Math.floor(time).toString();
      var estimatedTimeOfArrival = document.getElementById("estimatedTimeOfArrival");
      console.log(eta)
      if ((eta >= 60)) {
        var newEta = eta / 60; //minutes
        var mod = eta % 60; //seconds
        newEta = Math.floor(newEta);
        estimatedTimeOfArrival.value = newEta + "m " + mod + "s";
      } else {
        eta.toString();
        estimatedTimeOfArrival.value = eta + " s";
      }
      
      document.querySelector("#eta > span").innerHTML = estimatedTimeOfArrival.value;
    });
<form action="" id="findEta">
  <select name="origin" id="origin">

  </select>
  <select name="destination" id="destination">
    <option value="">Please Select Origin</option>
  </select>
  <input type="hidden" name="estimatedTimeOfArrival" id="estimatedTimeOfArrival">
  <div id="eta">ETA: <span></span></div>
</form>

Comments

0

It looks like what you're after is the Travelling Salesman problem. It's considered a difficult problem to solve, and probably something beyond the scope of a regular Stack Overflow answer, especially if it's going to be 24 cities (not so bad for 4 cities).

A good place to start is the Branch and Bound algorithm, again by no means trivial. Basically given a starting cities, we work out how to branch out to subsequent available cities in such a way with the lowest "cost" (distance or time) till we arrive at the destination city.

2 Comments

This seems to be variant of the traveling salesman problem called the "underperforming traveling salesman"... who only bothers to travel between neighboring points on a 4 node graph. He doesn't make many sales, but his travel cost trivially easy to compute. :-)
+1 haven't heard of the Underperforming Traveling Salesman problem (couldn't find it on Google either) but I get your point. I was assuming that these first 4 cities were only the first "branch" in OP's quest for a solution towards a 24-city problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.