Train Travel Planner

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
2
down vote

favorite












I did an exercise of a train travel planner. But it seems like a lot of code to do a simple thing? Is there a better way of writing the JavaScript?



Overview:
The planner needs to be able to find connecting station between origin and destination, then print out the traveling line. Also state how many stops there are.



Please see this JS fiddle containing my code for this exercise.



HTML:



<form id="trip-planner-form">
<label for="origin">Origin</label>
<select name="origin" id="origin"></select>
<label for="destination">Destination</label>
<select name="destination" id="destination"></select>
<button type="submit">Check</button>
</form>

<div id="planner-result"></div>


JS Code:



const data = [
id: 'alamein',
label: 'Alamein',
stops: [
'Flinders Street',
'Richmond',
'East Richmond',
'Burnley',
'Hawthorn',
'Glenferrie'
]
,
id: 'glen-waverly',
label: 'Glen Waverly',
stops: [
'Flagstaff',
'Melbourne Central',
'Parliament',
'Richmond',
'Kooyong and Tooronga'
]
,
id: 'sandringham',
label: 'Sandringham',
stops: [
'Southern Cross',
'Richmond',
'South Yarra',
'Prahran',
'Windsor'
]
];

const form_submit = document.getElementById('trip-planner-form');
const planner_result = document.getElementById('planner-result');
const origin_select = document.getElementById('origin');
const destination_select = document.getElementById('destination');


DOMReady();


function DOMReady()
console.log('dom ready');
loadStops(getStops(data));
set_planner_form_events();


function getStops(lines)
return lines.reduce((accum, current) =>
return accum.concat(current.stops);
, )
// remove duplicate
.filter((f, index, arr) =>
return arr.indexOf(f) === index;
).sort();


function loadStops(stops)

stops.forEach(stop =>
var stop_option = document.createElement('option');
stop_option.value = stop;
stop_option.textContent = stop;
// Append
origin_select.appendChild(stop_option);
destination_select.appendChild(stop_option.cloneNode(true));
);


function set_planner_form_events()
form_submit.addEventListener('submit', event =>
event.preventDefault();
print_planner_result();
);



function print_planner_result()
var origin = origin_select.value;
var destination = destination_select.value;
var result = '';

if (origin === destination)
result = 'You selected the same station.';
else
let traveling_stops = get_traveling_stops(origin, destination);

console.log(traveling_stops);

if (traveling_stops)
result = `<p>$traveling_stops.concat().join(' --> ')</p>`;
result += `<p>total: $traveling_stops.length stops </p>`;
else
result = 'Something went wrong.'




planner_result.innerHTML = result;



function get_traveling_stops(origin, destination)
// Find origin and destination index
var origin_line_index = data.findIndex(d => d.stops.indexOf(origin) > -1);
var dest_Line_index = data.findIndex(d => d.stops.indexOf(destination) > -1);

if (origin_line_index === -1


function get_connecting_station(line1, line2)

for (var i = 0; i < line1.stops.length; i++)
let stop_index = line2.stops.indexOf(line1.stops[i]);
if (stop_index > -1)
return line1.stops[i];



return false;







share|improve this question





















  • I don't think your planner works as intended. Given lines A-B, B-C, C-D, D-E, the plan for traveling from A to E is "A --> D --> E"?
    – le_m
    Jan 4 at 14:28











  • Did you assume that all destinations are at maximum one change of line away from any origin? Also, could it be that for Burnley -> Windsor, the stops Prahran and South Yarra are switched in the resulting travel plan?
    – le_m
    Jan 4 at 14:36











  • Welcome to Code Review! I changed the title so that it describes what the code does per site goals: "State what your code does in your title, not your main concerns about it.". Feel free to give it a different title if there is something more appropriate.
    – Sam Onela
    Jan 4 at 17:02
















up vote
2
down vote

favorite












I did an exercise of a train travel planner. But it seems like a lot of code to do a simple thing? Is there a better way of writing the JavaScript?



Overview:
The planner needs to be able to find connecting station between origin and destination, then print out the traveling line. Also state how many stops there are.



Please see this JS fiddle containing my code for this exercise.



HTML:



<form id="trip-planner-form">
<label for="origin">Origin</label>
<select name="origin" id="origin"></select>
<label for="destination">Destination</label>
<select name="destination" id="destination"></select>
<button type="submit">Check</button>
</form>

<div id="planner-result"></div>


JS Code:



const data = [
id: 'alamein',
label: 'Alamein',
stops: [
'Flinders Street',
'Richmond',
'East Richmond',
'Burnley',
'Hawthorn',
'Glenferrie'
]
,
id: 'glen-waverly',
label: 'Glen Waverly',
stops: [
'Flagstaff',
'Melbourne Central',
'Parliament',
'Richmond',
'Kooyong and Tooronga'
]
,
id: 'sandringham',
label: 'Sandringham',
stops: [
'Southern Cross',
'Richmond',
'South Yarra',
'Prahran',
'Windsor'
]
];

const form_submit = document.getElementById('trip-planner-form');
const planner_result = document.getElementById('planner-result');
const origin_select = document.getElementById('origin');
const destination_select = document.getElementById('destination');


DOMReady();


function DOMReady()
console.log('dom ready');
loadStops(getStops(data));
set_planner_form_events();


function getStops(lines)
return lines.reduce((accum, current) =>
return accum.concat(current.stops);
, )
// remove duplicate
.filter((f, index, arr) =>
return arr.indexOf(f) === index;
).sort();


function loadStops(stops)

stops.forEach(stop =>
var stop_option = document.createElement('option');
stop_option.value = stop;
stop_option.textContent = stop;
// Append
origin_select.appendChild(stop_option);
destination_select.appendChild(stop_option.cloneNode(true));
);


function set_planner_form_events()
form_submit.addEventListener('submit', event =>
event.preventDefault();
print_planner_result();
);



function print_planner_result()
var origin = origin_select.value;
var destination = destination_select.value;
var result = '';

if (origin === destination)
result = 'You selected the same station.';
else
let traveling_stops = get_traveling_stops(origin, destination);

console.log(traveling_stops);

if (traveling_stops)
result = `<p>$traveling_stops.concat().join(' --> ')</p>`;
result += `<p>total: $traveling_stops.length stops </p>`;
else
result = 'Something went wrong.'




planner_result.innerHTML = result;



function get_traveling_stops(origin, destination)
// Find origin and destination index
var origin_line_index = data.findIndex(d => d.stops.indexOf(origin) > -1);
var dest_Line_index = data.findIndex(d => d.stops.indexOf(destination) > -1);

if (origin_line_index === -1


function get_connecting_station(line1, line2)

for (var i = 0; i < line1.stops.length; i++)
let stop_index = line2.stops.indexOf(line1.stops[i]);
if (stop_index > -1)
return line1.stops[i];



return false;







share|improve this question





















  • I don't think your planner works as intended. Given lines A-B, B-C, C-D, D-E, the plan for traveling from A to E is "A --> D --> E"?
    – le_m
    Jan 4 at 14:28











  • Did you assume that all destinations are at maximum one change of line away from any origin? Also, could it be that for Burnley -> Windsor, the stops Prahran and South Yarra are switched in the resulting travel plan?
    – le_m
    Jan 4 at 14:36











  • Welcome to Code Review! I changed the title so that it describes what the code does per site goals: "State what your code does in your title, not your main concerns about it.". Feel free to give it a different title if there is something more appropriate.
    – Sam Onela
    Jan 4 at 17:02












up vote
2
down vote

favorite









up vote
2
down vote

favorite











I did an exercise of a train travel planner. But it seems like a lot of code to do a simple thing? Is there a better way of writing the JavaScript?



Overview:
The planner needs to be able to find connecting station between origin and destination, then print out the traveling line. Also state how many stops there are.



Please see this JS fiddle containing my code for this exercise.



HTML:



<form id="trip-planner-form">
<label for="origin">Origin</label>
<select name="origin" id="origin"></select>
<label for="destination">Destination</label>
<select name="destination" id="destination"></select>
<button type="submit">Check</button>
</form>

<div id="planner-result"></div>


JS Code:



const data = [
id: 'alamein',
label: 'Alamein',
stops: [
'Flinders Street',
'Richmond',
'East Richmond',
'Burnley',
'Hawthorn',
'Glenferrie'
]
,
id: 'glen-waverly',
label: 'Glen Waverly',
stops: [
'Flagstaff',
'Melbourne Central',
'Parliament',
'Richmond',
'Kooyong and Tooronga'
]
,
id: 'sandringham',
label: 'Sandringham',
stops: [
'Southern Cross',
'Richmond',
'South Yarra',
'Prahran',
'Windsor'
]
];

const form_submit = document.getElementById('trip-planner-form');
const planner_result = document.getElementById('planner-result');
const origin_select = document.getElementById('origin');
const destination_select = document.getElementById('destination');


DOMReady();


function DOMReady()
console.log('dom ready');
loadStops(getStops(data));
set_planner_form_events();


function getStops(lines)
return lines.reduce((accum, current) =>
return accum.concat(current.stops);
, )
// remove duplicate
.filter((f, index, arr) =>
return arr.indexOf(f) === index;
).sort();


function loadStops(stops)

stops.forEach(stop =>
var stop_option = document.createElement('option');
stop_option.value = stop;
stop_option.textContent = stop;
// Append
origin_select.appendChild(stop_option);
destination_select.appendChild(stop_option.cloneNode(true));
);


function set_planner_form_events()
form_submit.addEventListener('submit', event =>
event.preventDefault();
print_planner_result();
);



function print_planner_result()
var origin = origin_select.value;
var destination = destination_select.value;
var result = '';

if (origin === destination)
result = 'You selected the same station.';
else
let traveling_stops = get_traveling_stops(origin, destination);

console.log(traveling_stops);

if (traveling_stops)
result = `<p>$traveling_stops.concat().join(' --> ')</p>`;
result += `<p>total: $traveling_stops.length stops </p>`;
else
result = 'Something went wrong.'




planner_result.innerHTML = result;



function get_traveling_stops(origin, destination)
// Find origin and destination index
var origin_line_index = data.findIndex(d => d.stops.indexOf(origin) > -1);
var dest_Line_index = data.findIndex(d => d.stops.indexOf(destination) > -1);

if (origin_line_index === -1


function get_connecting_station(line1, line2)

for (var i = 0; i < line1.stops.length; i++)
let stop_index = line2.stops.indexOf(line1.stops[i]);
if (stop_index > -1)
return line1.stops[i];



return false;







share|improve this question













I did an exercise of a train travel planner. But it seems like a lot of code to do a simple thing? Is there a better way of writing the JavaScript?



Overview:
The planner needs to be able to find connecting station between origin and destination, then print out the traveling line. Also state how many stops there are.



Please see this JS fiddle containing my code for this exercise.



HTML:



<form id="trip-planner-form">
<label for="origin">Origin</label>
<select name="origin" id="origin"></select>
<label for="destination">Destination</label>
<select name="destination" id="destination"></select>
<button type="submit">Check</button>
</form>

<div id="planner-result"></div>


JS Code:



const data = [
id: 'alamein',
label: 'Alamein',
stops: [
'Flinders Street',
'Richmond',
'East Richmond',
'Burnley',
'Hawthorn',
'Glenferrie'
]
,
id: 'glen-waverly',
label: 'Glen Waverly',
stops: [
'Flagstaff',
'Melbourne Central',
'Parliament',
'Richmond',
'Kooyong and Tooronga'
]
,
id: 'sandringham',
label: 'Sandringham',
stops: [
'Southern Cross',
'Richmond',
'South Yarra',
'Prahran',
'Windsor'
]
];

const form_submit = document.getElementById('trip-planner-form');
const planner_result = document.getElementById('planner-result');
const origin_select = document.getElementById('origin');
const destination_select = document.getElementById('destination');


DOMReady();


function DOMReady()
console.log('dom ready');
loadStops(getStops(data));
set_planner_form_events();


function getStops(lines)
return lines.reduce((accum, current) =>
return accum.concat(current.stops);
, )
// remove duplicate
.filter((f, index, arr) =>
return arr.indexOf(f) === index;
).sort();


function loadStops(stops)

stops.forEach(stop =>
var stop_option = document.createElement('option');
stop_option.value = stop;
stop_option.textContent = stop;
// Append
origin_select.appendChild(stop_option);
destination_select.appendChild(stop_option.cloneNode(true));
);


function set_planner_form_events()
form_submit.addEventListener('submit', event =>
event.preventDefault();
print_planner_result();
);



function print_planner_result()
var origin = origin_select.value;
var destination = destination_select.value;
var result = '';

if (origin === destination)
result = 'You selected the same station.';
else
let traveling_stops = get_traveling_stops(origin, destination);

console.log(traveling_stops);

if (traveling_stops)
result = `<p>$traveling_stops.concat().join(' --> ')</p>`;
result += `<p>total: $traveling_stops.length stops </p>`;
else
result = 'Something went wrong.'




planner_result.innerHTML = result;



function get_traveling_stops(origin, destination)
// Find origin and destination index
var origin_line_index = data.findIndex(d => d.stops.indexOf(origin) > -1);
var dest_Line_index = data.findIndex(d => d.stops.indexOf(destination) > -1);

if (origin_line_index === -1


function get_connecting_station(line1, line2)

for (var i = 0; i < line1.stops.length; i++)
let stop_index = line2.stops.indexOf(line1.stops[i]);
if (stop_index > -1)
return line1.stops[i];



return false;









share|improve this question












share|improve this question




share|improve this question








edited Jan 4 at 17:01









Sam Onela

5,88461545




5,88461545









asked Jan 4 at 13:41









Ray Tsai

132




132











  • I don't think your planner works as intended. Given lines A-B, B-C, C-D, D-E, the plan for traveling from A to E is "A --> D --> E"?
    – le_m
    Jan 4 at 14:28











  • Did you assume that all destinations are at maximum one change of line away from any origin? Also, could it be that for Burnley -> Windsor, the stops Prahran and South Yarra are switched in the resulting travel plan?
    – le_m
    Jan 4 at 14:36











  • Welcome to Code Review! I changed the title so that it describes what the code does per site goals: "State what your code does in your title, not your main concerns about it.". Feel free to give it a different title if there is something more appropriate.
    – Sam Onela
    Jan 4 at 17:02
















  • I don't think your planner works as intended. Given lines A-B, B-C, C-D, D-E, the plan for traveling from A to E is "A --> D --> E"?
    – le_m
    Jan 4 at 14:28











  • Did you assume that all destinations are at maximum one change of line away from any origin? Also, could it be that for Burnley -> Windsor, the stops Prahran and South Yarra are switched in the resulting travel plan?
    – le_m
    Jan 4 at 14:36











  • Welcome to Code Review! I changed the title so that it describes what the code does per site goals: "State what your code does in your title, not your main concerns about it.". Feel free to give it a different title if there is something more appropriate.
    – Sam Onela
    Jan 4 at 17:02















I don't think your planner works as intended. Given lines A-B, B-C, C-D, D-E, the plan for traveling from A to E is "A --> D --> E"?
– le_m
Jan 4 at 14:28





I don't think your planner works as intended. Given lines A-B, B-C, C-D, D-E, the plan for traveling from A to E is "A --> D --> E"?
– le_m
Jan 4 at 14:28













Did you assume that all destinations are at maximum one change of line away from any origin? Also, could it be that for Burnley -> Windsor, the stops Prahran and South Yarra are switched in the resulting travel plan?
– le_m
Jan 4 at 14:36





Did you assume that all destinations are at maximum one change of line away from any origin? Also, could it be that for Burnley -> Windsor, the stops Prahran and South Yarra are switched in the resulting travel plan?
– le_m
Jan 4 at 14:36













Welcome to Code Review! I changed the title so that it describes what the code does per site goals: "State what your code does in your title, not your main concerns about it.". Feel free to give it a different title if there is something more appropriate.
– Sam Onela
Jan 4 at 17:02




Welcome to Code Review! I changed the title so that it describes what the code does per site goals: "State what your code does in your title, not your main concerns about it.". Feel free to give it a different title if there is something more appropriate.
– Sam Onela
Jan 4 at 17:02










1 Answer
1






active

oldest

votes

















up vote
-2
down vote



accepted










Simple solution



The problem is trivial as there is only one hub station. This means that there is only one root between any two stations.



You need only find which line each station is on. If not the same line then find the root on starting line to the hub and from the destination station hub to the destination station.



If the problem involved a configuration that allowed more than one root between stations it becomes much more involved but your code does not show that is an issue.



Simplify using functions.



The reason why your code seams long is because you have not compartmentalised functionality in the form of functions.



You can break it down to



  • Finding a line for a station

  • Getting stops between stations on a line

  • Finding a root between stations

  • Displaying a root.

By breaking the problem into smaller parts you reduce the overall complexity and make it easier to read and maintain.






function findLineForStation(station) 
return data.find(line => line.stops.includes(station));


function getStops(line, fromStation ,toStation, skipFirst = false)
const idxFrom = line.stops.indexOf(fromStation);
const idxTo = line.stops.indexOf(toStation);
const count = Math.abs(idxTo - idxFrom);
const dir = Math.sign(idxTo - idxFrom);
const stops = ;
var i;
for (i = skipFirst ? 1 : 0; i <= count; i ++)
stops.push(line.stops[idxFrom + i * dir]);

return stops;

function findRoot(fromStation, toStation)
const hubStation = "Richmond";
const fromLine = findLineForStation(fromStation);
const toLine = findLineForStation(toStation);
if (fromStation === hubStation) fromLine = toLine
if (fromLine === toLine)
return getStops(fromLine, fromStation, toStation);

return [
...getStops(fromLine, fromStation, hubStation),
...getStops(toLine, hubStation, toStation, true)
];

function displayRoot()
root.textContent = findRoot(originElId.value, destinationElId.value).join(" => ");


originElId.addEventListener("change",displayRoot);
destinationElId.addEventListener("change",displayRoot);
const data = [
id: 'alamein',
label: 'Alamein',
stops: ['Flinders Street', 'Richmond', 'East Richmond', 'Burnley', 'Hawthorn', 'Glenferrie']
,
id: 'glen-waverly',
label: 'Glen Waverly',
stops: ['Flagstaff', 'Melbourne Central', 'Parliament', 'Richmond', 'Kooyong and Tooronga']
,
id: 'sandringham',
label: 'Sandringham',
stops: ['Southern Cross', 'Richmond', 'South Yarra', 'Prahran', 'Windsor']
];

From <select name="origin" id="originElId"><option value="Burnley">Burnley</option><option value="East Richmond">East Richmond</option><option value="Flagstaff">Flagstaff</option><option value="Flinders Street">Flinders Street</option><option value="Glenferrie">Glenferrie</option><option value="Hawthorn">Hawthorn</option><option value="Kooyong and Tooronga">Kooyong and Tooronga</option><option value="Melbourne Central">Melbourne Central</option><option value="Parliament">Parliament</option><option value="Prahran">Prahran</option><option value="Richmond">Richmond</option><option value="South Yarra">South Yarra</option><option value="Southern Cross">Southern Cross</option><option value="Windsor">Windsor</option></select><br>
Destination <select name="destination" id="destinationElId"><option value="Burnley">Burnley</option><option value="East Richmond">East Richmond</option><option value="Flagstaff">Flagstaff</option><option value="Flinders Street">Flinders Street</option><option value="Glenferrie">Glenferrie</option><option value="Hawthorn">Hawthorn</option><option value="Kooyong and Tooronga">Kooyong and Tooronga</option><option value="Melbourne Central">Melbourne Central</option><option value="Parliament">Parliament</option><option value="Prahran">Prahran</option><option value="Richmond">Richmond</option><option value="South Yarra">South Yarra</option><option value="Southern Cross">Southern Cross</option><option value="Windsor">Windsor</option></select>
<div id="root"></div>








share|improve this answer























  • thanks a lot! This is pretty awesome. IDK why it was downvoted. I liked the use of Math.sign to solve the directional problem and use of Array.find() and Array.include() ... I should've used those! Im just gonna leave open for a bit to see if there are more different solutions :)
    – Ray Tsai
    Jan 4 at 22:41










Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f184281%2ftrain-travel-planner%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
-2
down vote



accepted










Simple solution



The problem is trivial as there is only one hub station. This means that there is only one root between any two stations.



You need only find which line each station is on. If not the same line then find the root on starting line to the hub and from the destination station hub to the destination station.



If the problem involved a configuration that allowed more than one root between stations it becomes much more involved but your code does not show that is an issue.



Simplify using functions.



The reason why your code seams long is because you have not compartmentalised functionality in the form of functions.



You can break it down to



  • Finding a line for a station

  • Getting stops between stations on a line

  • Finding a root between stations

  • Displaying a root.

By breaking the problem into smaller parts you reduce the overall complexity and make it easier to read and maintain.






function findLineForStation(station) 
return data.find(line => line.stops.includes(station));


function getStops(line, fromStation ,toStation, skipFirst = false)
const idxFrom = line.stops.indexOf(fromStation);
const idxTo = line.stops.indexOf(toStation);
const count = Math.abs(idxTo - idxFrom);
const dir = Math.sign(idxTo - idxFrom);
const stops = ;
var i;
for (i = skipFirst ? 1 : 0; i <= count; i ++)
stops.push(line.stops[idxFrom + i * dir]);

return stops;

function findRoot(fromStation, toStation)
const hubStation = "Richmond";
const fromLine = findLineForStation(fromStation);
const toLine = findLineForStation(toStation);
if (fromStation === hubStation) fromLine = toLine
if (fromLine === toLine)
return getStops(fromLine, fromStation, toStation);

return [
...getStops(fromLine, fromStation, hubStation),
...getStops(toLine, hubStation, toStation, true)
];

function displayRoot()
root.textContent = findRoot(originElId.value, destinationElId.value).join(" => ");


originElId.addEventListener("change",displayRoot);
destinationElId.addEventListener("change",displayRoot);
const data = [
id: 'alamein',
label: 'Alamein',
stops: ['Flinders Street', 'Richmond', 'East Richmond', 'Burnley', 'Hawthorn', 'Glenferrie']
,
id: 'glen-waverly',
label: 'Glen Waverly',
stops: ['Flagstaff', 'Melbourne Central', 'Parliament', 'Richmond', 'Kooyong and Tooronga']
,
id: 'sandringham',
label: 'Sandringham',
stops: ['Southern Cross', 'Richmond', 'South Yarra', 'Prahran', 'Windsor']
];

From <select name="origin" id="originElId"><option value="Burnley">Burnley</option><option value="East Richmond">East Richmond</option><option value="Flagstaff">Flagstaff</option><option value="Flinders Street">Flinders Street</option><option value="Glenferrie">Glenferrie</option><option value="Hawthorn">Hawthorn</option><option value="Kooyong and Tooronga">Kooyong and Tooronga</option><option value="Melbourne Central">Melbourne Central</option><option value="Parliament">Parliament</option><option value="Prahran">Prahran</option><option value="Richmond">Richmond</option><option value="South Yarra">South Yarra</option><option value="Southern Cross">Southern Cross</option><option value="Windsor">Windsor</option></select><br>
Destination <select name="destination" id="destinationElId"><option value="Burnley">Burnley</option><option value="East Richmond">East Richmond</option><option value="Flagstaff">Flagstaff</option><option value="Flinders Street">Flinders Street</option><option value="Glenferrie">Glenferrie</option><option value="Hawthorn">Hawthorn</option><option value="Kooyong and Tooronga">Kooyong and Tooronga</option><option value="Melbourne Central">Melbourne Central</option><option value="Parliament">Parliament</option><option value="Prahran">Prahran</option><option value="Richmond">Richmond</option><option value="South Yarra">South Yarra</option><option value="Southern Cross">Southern Cross</option><option value="Windsor">Windsor</option></select>
<div id="root"></div>








share|improve this answer























  • thanks a lot! This is pretty awesome. IDK why it was downvoted. I liked the use of Math.sign to solve the directional problem and use of Array.find() and Array.include() ... I should've used those! Im just gonna leave open for a bit to see if there are more different solutions :)
    – Ray Tsai
    Jan 4 at 22:41














up vote
-2
down vote



accepted










Simple solution



The problem is trivial as there is only one hub station. This means that there is only one root between any two stations.



You need only find which line each station is on. If not the same line then find the root on starting line to the hub and from the destination station hub to the destination station.



If the problem involved a configuration that allowed more than one root between stations it becomes much more involved but your code does not show that is an issue.



Simplify using functions.



The reason why your code seams long is because you have not compartmentalised functionality in the form of functions.



You can break it down to



  • Finding a line for a station

  • Getting stops between stations on a line

  • Finding a root between stations

  • Displaying a root.

By breaking the problem into smaller parts you reduce the overall complexity and make it easier to read and maintain.






function findLineForStation(station) 
return data.find(line => line.stops.includes(station));


function getStops(line, fromStation ,toStation, skipFirst = false)
const idxFrom = line.stops.indexOf(fromStation);
const idxTo = line.stops.indexOf(toStation);
const count = Math.abs(idxTo - idxFrom);
const dir = Math.sign(idxTo - idxFrom);
const stops = ;
var i;
for (i = skipFirst ? 1 : 0; i <= count; i ++)
stops.push(line.stops[idxFrom + i * dir]);

return stops;

function findRoot(fromStation, toStation)
const hubStation = "Richmond";
const fromLine = findLineForStation(fromStation);
const toLine = findLineForStation(toStation);
if (fromStation === hubStation) fromLine = toLine
if (fromLine === toLine)
return getStops(fromLine, fromStation, toStation);

return [
...getStops(fromLine, fromStation, hubStation),
...getStops(toLine, hubStation, toStation, true)
];

function displayRoot()
root.textContent = findRoot(originElId.value, destinationElId.value).join(" => ");


originElId.addEventListener("change",displayRoot);
destinationElId.addEventListener("change",displayRoot);
const data = [
id: 'alamein',
label: 'Alamein',
stops: ['Flinders Street', 'Richmond', 'East Richmond', 'Burnley', 'Hawthorn', 'Glenferrie']
,
id: 'glen-waverly',
label: 'Glen Waverly',
stops: ['Flagstaff', 'Melbourne Central', 'Parliament', 'Richmond', 'Kooyong and Tooronga']
,
id: 'sandringham',
label: 'Sandringham',
stops: ['Southern Cross', 'Richmond', 'South Yarra', 'Prahran', 'Windsor']
];

From <select name="origin" id="originElId"><option value="Burnley">Burnley</option><option value="East Richmond">East Richmond</option><option value="Flagstaff">Flagstaff</option><option value="Flinders Street">Flinders Street</option><option value="Glenferrie">Glenferrie</option><option value="Hawthorn">Hawthorn</option><option value="Kooyong and Tooronga">Kooyong and Tooronga</option><option value="Melbourne Central">Melbourne Central</option><option value="Parliament">Parliament</option><option value="Prahran">Prahran</option><option value="Richmond">Richmond</option><option value="South Yarra">South Yarra</option><option value="Southern Cross">Southern Cross</option><option value="Windsor">Windsor</option></select><br>
Destination <select name="destination" id="destinationElId"><option value="Burnley">Burnley</option><option value="East Richmond">East Richmond</option><option value="Flagstaff">Flagstaff</option><option value="Flinders Street">Flinders Street</option><option value="Glenferrie">Glenferrie</option><option value="Hawthorn">Hawthorn</option><option value="Kooyong and Tooronga">Kooyong and Tooronga</option><option value="Melbourne Central">Melbourne Central</option><option value="Parliament">Parliament</option><option value="Prahran">Prahran</option><option value="Richmond">Richmond</option><option value="South Yarra">South Yarra</option><option value="Southern Cross">Southern Cross</option><option value="Windsor">Windsor</option></select>
<div id="root"></div>








share|improve this answer























  • thanks a lot! This is pretty awesome. IDK why it was downvoted. I liked the use of Math.sign to solve the directional problem and use of Array.find() and Array.include() ... I should've used those! Im just gonna leave open for a bit to see if there are more different solutions :)
    – Ray Tsai
    Jan 4 at 22:41












up vote
-2
down vote



accepted







up vote
-2
down vote



accepted






Simple solution



The problem is trivial as there is only one hub station. This means that there is only one root between any two stations.



You need only find which line each station is on. If not the same line then find the root on starting line to the hub and from the destination station hub to the destination station.



If the problem involved a configuration that allowed more than one root between stations it becomes much more involved but your code does not show that is an issue.



Simplify using functions.



The reason why your code seams long is because you have not compartmentalised functionality in the form of functions.



You can break it down to



  • Finding a line for a station

  • Getting stops between stations on a line

  • Finding a root between stations

  • Displaying a root.

By breaking the problem into smaller parts you reduce the overall complexity and make it easier to read and maintain.






function findLineForStation(station) 
return data.find(line => line.stops.includes(station));


function getStops(line, fromStation ,toStation, skipFirst = false)
const idxFrom = line.stops.indexOf(fromStation);
const idxTo = line.stops.indexOf(toStation);
const count = Math.abs(idxTo - idxFrom);
const dir = Math.sign(idxTo - idxFrom);
const stops = ;
var i;
for (i = skipFirst ? 1 : 0; i <= count; i ++)
stops.push(line.stops[idxFrom + i * dir]);

return stops;

function findRoot(fromStation, toStation)
const hubStation = "Richmond";
const fromLine = findLineForStation(fromStation);
const toLine = findLineForStation(toStation);
if (fromStation === hubStation) fromLine = toLine
if (fromLine === toLine)
return getStops(fromLine, fromStation, toStation);

return [
...getStops(fromLine, fromStation, hubStation),
...getStops(toLine, hubStation, toStation, true)
];

function displayRoot()
root.textContent = findRoot(originElId.value, destinationElId.value).join(" => ");


originElId.addEventListener("change",displayRoot);
destinationElId.addEventListener("change",displayRoot);
const data = [
id: 'alamein',
label: 'Alamein',
stops: ['Flinders Street', 'Richmond', 'East Richmond', 'Burnley', 'Hawthorn', 'Glenferrie']
,
id: 'glen-waverly',
label: 'Glen Waverly',
stops: ['Flagstaff', 'Melbourne Central', 'Parliament', 'Richmond', 'Kooyong and Tooronga']
,
id: 'sandringham',
label: 'Sandringham',
stops: ['Southern Cross', 'Richmond', 'South Yarra', 'Prahran', 'Windsor']
];

From <select name="origin" id="originElId"><option value="Burnley">Burnley</option><option value="East Richmond">East Richmond</option><option value="Flagstaff">Flagstaff</option><option value="Flinders Street">Flinders Street</option><option value="Glenferrie">Glenferrie</option><option value="Hawthorn">Hawthorn</option><option value="Kooyong and Tooronga">Kooyong and Tooronga</option><option value="Melbourne Central">Melbourne Central</option><option value="Parliament">Parliament</option><option value="Prahran">Prahran</option><option value="Richmond">Richmond</option><option value="South Yarra">South Yarra</option><option value="Southern Cross">Southern Cross</option><option value="Windsor">Windsor</option></select><br>
Destination <select name="destination" id="destinationElId"><option value="Burnley">Burnley</option><option value="East Richmond">East Richmond</option><option value="Flagstaff">Flagstaff</option><option value="Flinders Street">Flinders Street</option><option value="Glenferrie">Glenferrie</option><option value="Hawthorn">Hawthorn</option><option value="Kooyong and Tooronga">Kooyong and Tooronga</option><option value="Melbourne Central">Melbourne Central</option><option value="Parliament">Parliament</option><option value="Prahran">Prahran</option><option value="Richmond">Richmond</option><option value="South Yarra">South Yarra</option><option value="Southern Cross">Southern Cross</option><option value="Windsor">Windsor</option></select>
<div id="root"></div>








share|improve this answer















Simple solution



The problem is trivial as there is only one hub station. This means that there is only one root between any two stations.



You need only find which line each station is on. If not the same line then find the root on starting line to the hub and from the destination station hub to the destination station.



If the problem involved a configuration that allowed more than one root between stations it becomes much more involved but your code does not show that is an issue.



Simplify using functions.



The reason why your code seams long is because you have not compartmentalised functionality in the form of functions.



You can break it down to



  • Finding a line for a station

  • Getting stops between stations on a line

  • Finding a root between stations

  • Displaying a root.

By breaking the problem into smaller parts you reduce the overall complexity and make it easier to read and maintain.






function findLineForStation(station) 
return data.find(line => line.stops.includes(station));


function getStops(line, fromStation ,toStation, skipFirst = false)
const idxFrom = line.stops.indexOf(fromStation);
const idxTo = line.stops.indexOf(toStation);
const count = Math.abs(idxTo - idxFrom);
const dir = Math.sign(idxTo - idxFrom);
const stops = ;
var i;
for (i = skipFirst ? 1 : 0; i <= count; i ++)
stops.push(line.stops[idxFrom + i * dir]);

return stops;

function findRoot(fromStation, toStation)
const hubStation = "Richmond";
const fromLine = findLineForStation(fromStation);
const toLine = findLineForStation(toStation);
if (fromStation === hubStation) fromLine = toLine
if (fromLine === toLine)
return getStops(fromLine, fromStation, toStation);

return [
...getStops(fromLine, fromStation, hubStation),
...getStops(toLine, hubStation, toStation, true)
];

function displayRoot()
root.textContent = findRoot(originElId.value, destinationElId.value).join(" => ");


originElId.addEventListener("change",displayRoot);
destinationElId.addEventListener("change",displayRoot);
const data = [
id: 'alamein',
label: 'Alamein',
stops: ['Flinders Street', 'Richmond', 'East Richmond', 'Burnley', 'Hawthorn', 'Glenferrie']
,
id: 'glen-waverly',
label: 'Glen Waverly',
stops: ['Flagstaff', 'Melbourne Central', 'Parliament', 'Richmond', 'Kooyong and Tooronga']
,
id: 'sandringham',
label: 'Sandringham',
stops: ['Southern Cross', 'Richmond', 'South Yarra', 'Prahran', 'Windsor']
];

From <select name="origin" id="originElId"><option value="Burnley">Burnley</option><option value="East Richmond">East Richmond</option><option value="Flagstaff">Flagstaff</option><option value="Flinders Street">Flinders Street</option><option value="Glenferrie">Glenferrie</option><option value="Hawthorn">Hawthorn</option><option value="Kooyong and Tooronga">Kooyong and Tooronga</option><option value="Melbourne Central">Melbourne Central</option><option value="Parliament">Parliament</option><option value="Prahran">Prahran</option><option value="Richmond">Richmond</option><option value="South Yarra">South Yarra</option><option value="Southern Cross">Southern Cross</option><option value="Windsor">Windsor</option></select><br>
Destination <select name="destination" id="destinationElId"><option value="Burnley">Burnley</option><option value="East Richmond">East Richmond</option><option value="Flagstaff">Flagstaff</option><option value="Flinders Street">Flinders Street</option><option value="Glenferrie">Glenferrie</option><option value="Hawthorn">Hawthorn</option><option value="Kooyong and Tooronga">Kooyong and Tooronga</option><option value="Melbourne Central">Melbourne Central</option><option value="Parliament">Parliament</option><option value="Prahran">Prahran</option><option value="Richmond">Richmond</option><option value="South Yarra">South Yarra</option><option value="Southern Cross">Southern Cross</option><option value="Windsor">Windsor</option></select>
<div id="root"></div>








function findLineForStation(station) 
return data.find(line => line.stops.includes(station));


function getStops(line, fromStation ,toStation, skipFirst = false)
const idxFrom = line.stops.indexOf(fromStation);
const idxTo = line.stops.indexOf(toStation);
const count = Math.abs(idxTo - idxFrom);
const dir = Math.sign(idxTo - idxFrom);
const stops = ;
var i;
for (i = skipFirst ? 1 : 0; i <= count; i ++)
stops.push(line.stops[idxFrom + i * dir]);

return stops;

function findRoot(fromStation, toStation)
const hubStation = "Richmond";
const fromLine = findLineForStation(fromStation);
const toLine = findLineForStation(toStation);
if (fromStation === hubStation) fromLine = toLine
if (fromLine === toLine)
return getStops(fromLine, fromStation, toStation);

return [
...getStops(fromLine, fromStation, hubStation),
...getStops(toLine, hubStation, toStation, true)
];

function displayRoot()
root.textContent = findRoot(originElId.value, destinationElId.value).join(" => ");


originElId.addEventListener("change",displayRoot);
destinationElId.addEventListener("change",displayRoot);
const data = [
id: 'alamein',
label: 'Alamein',
stops: ['Flinders Street', 'Richmond', 'East Richmond', 'Burnley', 'Hawthorn', 'Glenferrie']
,
id: 'glen-waverly',
label: 'Glen Waverly',
stops: ['Flagstaff', 'Melbourne Central', 'Parliament', 'Richmond', 'Kooyong and Tooronga']
,
id: 'sandringham',
label: 'Sandringham',
stops: ['Southern Cross', 'Richmond', 'South Yarra', 'Prahran', 'Windsor']
];

From <select name="origin" id="originElId"><option value="Burnley">Burnley</option><option value="East Richmond">East Richmond</option><option value="Flagstaff">Flagstaff</option><option value="Flinders Street">Flinders Street</option><option value="Glenferrie">Glenferrie</option><option value="Hawthorn">Hawthorn</option><option value="Kooyong and Tooronga">Kooyong and Tooronga</option><option value="Melbourne Central">Melbourne Central</option><option value="Parliament">Parliament</option><option value="Prahran">Prahran</option><option value="Richmond">Richmond</option><option value="South Yarra">South Yarra</option><option value="Southern Cross">Southern Cross</option><option value="Windsor">Windsor</option></select><br>
Destination <select name="destination" id="destinationElId"><option value="Burnley">Burnley</option><option value="East Richmond">East Richmond</option><option value="Flagstaff">Flagstaff</option><option value="Flinders Street">Flinders Street</option><option value="Glenferrie">Glenferrie</option><option value="Hawthorn">Hawthorn</option><option value="Kooyong and Tooronga">Kooyong and Tooronga</option><option value="Melbourne Central">Melbourne Central</option><option value="Parliament">Parliament</option><option value="Prahran">Prahran</option><option value="Richmond">Richmond</option><option value="South Yarra">South Yarra</option><option value="Southern Cross">Southern Cross</option><option value="Windsor">Windsor</option></select>
<div id="root"></div>





function findLineForStation(station) 
return data.find(line => line.stops.includes(station));


function getStops(line, fromStation ,toStation, skipFirst = false)
const idxFrom = line.stops.indexOf(fromStation);
const idxTo = line.stops.indexOf(toStation);
const count = Math.abs(idxTo - idxFrom);
const dir = Math.sign(idxTo - idxFrom);
const stops = ;
var i;
for (i = skipFirst ? 1 : 0; i <= count; i ++)
stops.push(line.stops[idxFrom + i * dir]);

return stops;

function findRoot(fromStation, toStation)
const hubStation = "Richmond";
const fromLine = findLineForStation(fromStation);
const toLine = findLineForStation(toStation);
if (fromStation === hubStation) fromLine = toLine
if (fromLine === toLine)
return getStops(fromLine, fromStation, toStation);

return [
...getStops(fromLine, fromStation, hubStation),
...getStops(toLine, hubStation, toStation, true)
];

function displayRoot()
root.textContent = findRoot(originElId.value, destinationElId.value).join(" => ");


originElId.addEventListener("change",displayRoot);
destinationElId.addEventListener("change",displayRoot);
const data = [
id: 'alamein',
label: 'Alamein',
stops: ['Flinders Street', 'Richmond', 'East Richmond', 'Burnley', 'Hawthorn', 'Glenferrie']
,
id: 'glen-waverly',
label: 'Glen Waverly',
stops: ['Flagstaff', 'Melbourne Central', 'Parliament', 'Richmond', 'Kooyong and Tooronga']
,
id: 'sandringham',
label: 'Sandringham',
stops: ['Southern Cross', 'Richmond', 'South Yarra', 'Prahran', 'Windsor']
];

From <select name="origin" id="originElId"><option value="Burnley">Burnley</option><option value="East Richmond">East Richmond</option><option value="Flagstaff">Flagstaff</option><option value="Flinders Street">Flinders Street</option><option value="Glenferrie">Glenferrie</option><option value="Hawthorn">Hawthorn</option><option value="Kooyong and Tooronga">Kooyong and Tooronga</option><option value="Melbourne Central">Melbourne Central</option><option value="Parliament">Parliament</option><option value="Prahran">Prahran</option><option value="Richmond">Richmond</option><option value="South Yarra">South Yarra</option><option value="Southern Cross">Southern Cross</option><option value="Windsor">Windsor</option></select><br>
Destination <select name="destination" id="destinationElId"><option value="Burnley">Burnley</option><option value="East Richmond">East Richmond</option><option value="Flagstaff">Flagstaff</option><option value="Flinders Street">Flinders Street</option><option value="Glenferrie">Glenferrie</option><option value="Hawthorn">Hawthorn</option><option value="Kooyong and Tooronga">Kooyong and Tooronga</option><option value="Melbourne Central">Melbourne Central</option><option value="Parliament">Parliament</option><option value="Prahran">Prahran</option><option value="Richmond">Richmond</option><option value="South Yarra">South Yarra</option><option value="Southern Cross">Southern Cross</option><option value="Windsor">Windsor</option></select>
<div id="root"></div>






share|improve this answer















share|improve this answer



share|improve this answer








edited Jan 4 at 17:21


























answered Jan 4 at 16:42









Blindman67

5,4251320




5,4251320











  • thanks a lot! This is pretty awesome. IDK why it was downvoted. I liked the use of Math.sign to solve the directional problem and use of Array.find() and Array.include() ... I should've used those! Im just gonna leave open for a bit to see if there are more different solutions :)
    – Ray Tsai
    Jan 4 at 22:41
















  • thanks a lot! This is pretty awesome. IDK why it was downvoted. I liked the use of Math.sign to solve the directional problem and use of Array.find() and Array.include() ... I should've used those! Im just gonna leave open for a bit to see if there are more different solutions :)
    – Ray Tsai
    Jan 4 at 22:41















thanks a lot! This is pretty awesome. IDK why it was downvoted. I liked the use of Math.sign to solve the directional problem and use of Array.find() and Array.include() ... I should've used those! Im just gonna leave open for a bit to see if there are more different solutions :)
– Ray Tsai
Jan 4 at 22:41




thanks a lot! This is pretty awesome. IDK why it was downvoted. I liked the use of Math.sign to solve the directional problem and use of Array.find() and Array.include() ... I should've used those! Im just gonna leave open for a bit to see if there are more different solutions :)
– Ray Tsai
Jan 4 at 22:41












 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f184281%2ftrain-travel-planner%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Greedy Best First Search implementation in Rust

Function to Return a JSON Like Objects Using VBA Collections and Arrays

C++11 CLH Lock Implementation