I'm having trouble understanding what's happening in the opening bit of code in Eloquent Javascript's Chapter 7.
const roads = [
"Alice's House-Bob's House", "Alice's House-Cabin",
"Alice's House-Post Office", "Bob's House-Town Hall",
"Daria's House-Ernie's House", "Daria's House-Town Hall",
"Ernie's House-Grete's House", "Grete's House-Farm",
"Grete's House-Shop", "Marketplace-Farm",
"Marketplace-Post Office", "Marketplace-Shop",
"Marketplace-Town Hall", "Shop-Town Hall"
];
function buildGraph(edges) {
let graph = Object.create(null);
function addEdge(from, to) {
if (graph[from] == null) {
graph[from] = [to];
} else {
graph[from].push(to);
}
}
for (let [from, to] of edges.map(r => r.split("-"))) {
addEdge(from, to);
addEdge(to, from);
}
return graph;
}
const roadGraph = buildGraph(roads);
The following explanation, as provided in this post, makes sense in and of itself:
For example, the first three iterations will build connections from Alice's House. The first to is Bob's House. So graph["Alice's House"] is undefined, and we put ["Bob's House"] there. In the next iteration, it's from Alice's House to Cabin; but now graph["Alice's House"] is not empty, so we append to it, resulting in ["Bob's House", "Cabin"]. At the end of the run, we'll know that if we're at Alice's House, there's three possible places we can go (Bob's House, Cabin and Post Office).
I'm confident I understand the logic behind how the array is populated. But here's what I don't understand:
Could someone please perhaps walk me through the first couple of iterations in more detail? I've spent a great deal of time trying to work this out but feel like I've reached a dead end.
In this snippet the flow steps are printed out. See the comments in the snippet for some explanation.
To play around with this code I've created a Stackblitz project.
const log = Log();
const roads = [
"Alice's House-Bob's House", "Alice's House-Cabin",
"Alice's House-Post Office", "Bob's House-Town Hall",
];
const connections = buildGraph(roads);
log(` `, `**Result**`, JSON.stringify(connections, null, 2));
function buildGraph(edges) {
const graph = {};
/*
[from] and [to] are strings sent from the (for) loop
if [graph] contains a key [from], its value is an array,
so [to] is concatted to it. Otherwise graph[from]'s value
will be a new array, with first value [to]
In other words: [from] is always the key (a string), added if
non existent in [graph], or supplemented with the
value of [to]
*/
const addEdge = (from, to) => {
const exists = from in graph;
log(`<code>graph['${from}']</code> exists?${ exists
? ` yep.`
: ` nope. (graph['${from}'] will be added with ["${to}"] as value.`}`);
graph[from] = graph[from] ? graph[from].concat([to]) : [to];
log(` <code>graph['${from}']</code> value now ${JSON.stringify(graph[from])}`);
}
// for every pair of strings from the splitted value of every element
// of [roads] ...
for (let [from, to] of edges.map(r => r.split(`-`))) {
addEdge(from, to);
addEdge(to, from);
}
return graph;
}
// for demo
function Log() {
const res = document.querySelector('#result');
return (...args) => {
args.forEach(arg =>
res.appendChild(
Object.assign(document.createElement(`div`), {
innerHTML: `${arg}`,
className: `logEntry`
})
))
};
}
body {
font: normal 12px/16px verdana, arial;
}
.logEntry {
margin: 5px 0;
}
code {
background-color: #eee;
color: green;
padding: 1px 2px;
}
<pre id="result"></pre>