mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-02-21 11:04:47 -05:00
feat(curriculum): add shortest path algorithm python project (#52634)
Co-authored-by: Dario-DC <dicillodario@gmail.com> Co-authored-by: Dario-DC <105294544+Dario-DC@users.noreply.github.com> Co-authored-by: Zaira <33151350+zairahira@users.noreply.github.com> Co-authored-by: Shaun Hamilton <shauhami020@gmail.com> Co-authored-by: Ihechikara Vincent Abba <ihechikara.dev@gmail.com>
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Introduction to the Learn Algorithm Design by Building the Shortest Path Algorithm
|
||||
block: learn-algorithm-design-by-building-the-shortest-path-algorithm
|
||||
superBlock: upcoming-python
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Introduction to the Learn Algorithm Design by Building the Shortest Path Algorithm
|
||||
|
||||
This is a test for the new project-based curriculum.
|
||||
@@ -0,0 +1,232 @@
|
||||
{
|
||||
"name": "Learn Algorithm Design by Building the Shortest Path Algorithm",
|
||||
"isUpcomingChange": false,
|
||||
"usesMultifileEditor": true,
|
||||
"hasEditableBoundaries": true,
|
||||
"dashedName": "learn-algorithm-design-by-building-the-shortest-path-algorithm",
|
||||
"order": 5,
|
||||
"time": "5 hours",
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "scientific-computing-with-python",
|
||||
"isBeta": true,
|
||||
"challengeOrder": [
|
||||
{
|
||||
"id": "65789506b30453080f77470c",
|
||||
"title": "Step 1"
|
||||
},
|
||||
{
|
||||
"id": "65576ff7888f9e96f52a4be1",
|
||||
"title": "Step 2"
|
||||
},
|
||||
{
|
||||
"id": "6578b13757611e2825beb8a5",
|
||||
"title": "Step 3"
|
||||
},
|
||||
{
|
||||
"id": "6578b57361f2f132a02e2a18",
|
||||
"title": "Step 4"
|
||||
},
|
||||
{
|
||||
"id": "65796fac81f983127558f3f4",
|
||||
"title": "Step 5"
|
||||
},
|
||||
{
|
||||
"id": "6579717f0920131304286804",
|
||||
"title": "Step 6"
|
||||
},
|
||||
{
|
||||
"id": "65797670e0c0d016f17e7660",
|
||||
"title": "Step 7"
|
||||
},
|
||||
{
|
||||
"id": "6579ca0923cfa7162089d2f0",
|
||||
"title": "Step 8"
|
||||
},
|
||||
{
|
||||
"id": "6579cbab9825b8170974c69a",
|
||||
"title": "Step 9"
|
||||
},
|
||||
{
|
||||
"id": "6579cd5f6dd62c189e53ddbb",
|
||||
"title": "Step 10"
|
||||
},
|
||||
{
|
||||
"id": "6579dd49fa8a8e1fd06b85a9",
|
||||
"title": "Step 11"
|
||||
},
|
||||
{
|
||||
"id": "6557709b0aee699a6a00528c",
|
||||
"title": "Step 12"
|
||||
},
|
||||
{
|
||||
"id": "6557712d77ce2d9bd7e63afd",
|
||||
"title": "Step 13"
|
||||
},
|
||||
{
|
||||
"id": "6557716aadbd2d9c42c0e69a",
|
||||
"title": "Step 14"
|
||||
},
|
||||
{
|
||||
"id": "655771d889132f9ccd341060",
|
||||
"title": "Step 15"
|
||||
},
|
||||
{
|
||||
"id": "6566195b0a021bb660b2b4b1",
|
||||
"title": "Step 16"
|
||||
},
|
||||
{
|
||||
"id": "65661b72d6745ebec6a96923",
|
||||
"title": "Step 17"
|
||||
},
|
||||
{
|
||||
"id": "65577236b056379d5dbc7000",
|
||||
"title": "Step 18"
|
||||
},
|
||||
{
|
||||
"id": "655773b0591c5f9f4045883e",
|
||||
"title": "Step 19"
|
||||
},
|
||||
{
|
||||
"id": "655773f8b8b5db9fc6d0ae76",
|
||||
"title": "Step 20"
|
||||
},
|
||||
{
|
||||
"id": "6557743527cb92a06417ea97",
|
||||
"title": "Step 21"
|
||||
},
|
||||
{
|
||||
"id": "6557746aad2844a0cd864e12",
|
||||
"title": "Step 22"
|
||||
},
|
||||
{
|
||||
"id": "655774955b097ea14897db12",
|
||||
"title": "Step 23"
|
||||
},
|
||||
{
|
||||
"id": "655774d01daeeaa1978b99d5",
|
||||
"title": "Step 24"
|
||||
},
|
||||
{
|
||||
"id": "655775221059f5a20493d5d7",
|
||||
"title": "Step 25"
|
||||
},
|
||||
{
|
||||
"id": "655776db1eeae0a620e42a0d",
|
||||
"title": "Step 26"
|
||||
},
|
||||
{
|
||||
"id": "655777060d8ddea6741be1b1",
|
||||
"title": "Step 27"
|
||||
},
|
||||
{
|
||||
"id": "65577739f57ecca6c39bb4e9",
|
||||
"title": "Step 28"
|
||||
},
|
||||
{
|
||||
"id": "65577791ad8c26a7705e2919",
|
||||
"title": "Step 29"
|
||||
},
|
||||
{
|
||||
"id": "65577a17564ce8a8e06c1460",
|
||||
"title": "Step 30"
|
||||
},
|
||||
{
|
||||
"id": "65578c17d54dfab65cd54b95",
|
||||
"title": "Step 31"
|
||||
},
|
||||
{
|
||||
"id": "65578c74607d40b6d8c4757f",
|
||||
"title": "Step 32"
|
||||
},
|
||||
{
|
||||
"id": "65578cb031cd93b77a285db2",
|
||||
"title": "Step 33"
|
||||
},
|
||||
{
|
||||
"id": "65578cee7f2cb8b80127cce2",
|
||||
"title": "Step 34"
|
||||
},
|
||||
{
|
||||
"id": "65578d0f6c78a0b868a43b9c",
|
||||
"title": "Step 35"
|
||||
},
|
||||
{
|
||||
"id": "65578d4fc3afc3b8f554c882",
|
||||
"title": "Step 36"
|
||||
},
|
||||
{
|
||||
"id": "65578f895f2a65ba7a916804",
|
||||
"title": "Step 37"
|
||||
},
|
||||
{
|
||||
"id": "65578fcf00322dbad5dee05b",
|
||||
"title": "Step 38"
|
||||
},
|
||||
{
|
||||
"id": "657891ab9c1903f4e55433ba",
|
||||
"title": "Step 39"
|
||||
},
|
||||
{
|
||||
"id": "655790d113d14dbb727eaf41",
|
||||
"title": "Step 40"
|
||||
},
|
||||
{
|
||||
"id": "6557910b0ebaeebc18209e90",
|
||||
"title": "Step 41"
|
||||
},
|
||||
{
|
||||
"id": "6557913b8fe5c0bc834c9f4f",
|
||||
"title": "Step 42"
|
||||
},
|
||||
{
|
||||
"id": "655791847db8a9bd0b685f40",
|
||||
"title": "Step 43"
|
||||
},
|
||||
{
|
||||
"id": "655791ae44c182bd92f31caa",
|
||||
"title": "Step 44"
|
||||
},
|
||||
{
|
||||
"id": "655791e6cf5e03be3de73451",
|
||||
"title": "Step 45"
|
||||
},
|
||||
{
|
||||
"id": "6567722f53ad97d7ea6bb082",
|
||||
"title": "Step 46"
|
||||
},
|
||||
{
|
||||
"id": "65579228c669fcbebffd01d5",
|
||||
"title": "Step 47"
|
||||
},
|
||||
{
|
||||
"id": "6557924d47c325bf27afbe51",
|
||||
"title": "Step 48"
|
||||
},
|
||||
{
|
||||
"id": "6559d70c5161b16ff1d6530d",
|
||||
"title": "Step 49"
|
||||
},
|
||||
{
|
||||
"id": "6557927ad11e58bf8c794b25",
|
||||
"title": "Step 50"
|
||||
},
|
||||
{
|
||||
"id": "6559d86fe1b8947954b9178d",
|
||||
"title": "Step 51"
|
||||
},
|
||||
{
|
||||
"id": "6559da1b7d75f088f5e6b89f",
|
||||
"title": "Step 52"
|
||||
},
|
||||
{
|
||||
"id": "65774ae7c3eee66fe79b9459",
|
||||
"title": "Step 53"
|
||||
},
|
||||
{
|
||||
"id": "6559da93115de78dbbdc7ba3",
|
||||
"title": "Step 54"
|
||||
}
|
||||
],
|
||||
"helpCategory": "Python"
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
id: 65576ff7888f9e96f52a4be1
|
||||
title: Step 2
|
||||
challengeType: 20
|
||||
dashedName: step-2
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Dictionaries store data in the form of *key*-*value* pairs. A key is separated from the correspondent value by a colon. And each key-value pair is separated from the following pair by a comma:
|
||||
|
||||
```py
|
||||
my_dict = {
|
||||
'name': 'Michael',
|
||||
'occupation': 'Lumberjack'
|
||||
}
|
||||
```
|
||||
|
||||
Add a new key-value pair to your dictionary. Use the string `species` as the key, and the string `guinea pig` as the value.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add a new key-value pair to your `copper` dictionary.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
copper = __locals.get("copper")
|
||||
len(copper) == 1
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should have a `species` key with the value `guinea pig` inside your `copper` dictionary.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
copper = __locals.get("copper")
|
||||
copper == {"species": "guinea pig"}
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
copper = {}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
id: 6557709b0aee699a6a00528c
|
||||
title: Step 12
|
||||
challengeType: 20
|
||||
dashedName: step-12
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now, replace the existent keys with the strings `A` and `B` — one for each node. Then, replace each value with the string representing the node connected to the key.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your dictionary should have an `A` key.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
"A" in graph
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
Your `A` key should have `B` as the value.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
graph["A"] == "B"
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
Your dictionary should have an `B` key.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
"B" in graph
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
Your `B` key should have `A` as the value.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
graph["B"] == "A"
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
Your dictionary should have two keys.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
len(graph) == 2
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
my_graph = {
|
||||
'species': 'guinea pig',
|
||||
'age': 2
|
||||
}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,78 @@
|
||||
---
|
||||
id: 6557712d77ce2d9bd7e63afd
|
||||
title: Step 13
|
||||
challengeType: 20
|
||||
dashedName: step-13
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Add another node connected to `B` to your graph and call it `C`.
|
||||
|
||||
Modify your existing dictionary to represent this arrangement. Use a list to represent the multiple connections of your `B` node.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your dictionary should have 3 keys — `A`, `B`, and `C`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
key_list = ["A", "B", "C"]
|
||||
len(graph) == 3 and all(key in graph for key in key_list)
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["A"]` should have the `B` node as the value.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
graph["A"] == "B"
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["B"]` should be a list.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
type(graph["B"]) is list
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
The value of `my_graph["B"]` should be a list containing the other two nodes.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
len(graph["B"]) == 2 and "A" in graph["B"] and "C" in graph["B"]
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
The value of `my_graph["C"]` should be the connected node.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
graph["C"] == "B"
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
my_graph = {
|
||||
'A': 'B',
|
||||
'B': 'A'
|
||||
}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
id: 6557716aadbd2d9c42c0e69a
|
||||
title: Step 14
|
||||
challengeType: 20
|
||||
dashedName: step-14
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Add one last node, `D`, which is connected with `A` and `C`. Modify your dictionary to represent this structure. Again, use a list to represent multiple connections.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your dictionary should have 4 keys called `A`, `B`, `C`, and `D`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
key_list = ["A", "B", "C", "D"]
|
||||
len(graph) == 4 and all(key in graph for key in key_list)
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["A"]` should be a list.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
type(graph["A"]) is list
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["A"]` should be a list containing `B` and `D`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
len(graph["A"]) == 2 and "B" in graph["A"] and "D" in graph["A"]
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["B"]` should be a list.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
type(graph["B"]) is list
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["B"]` should be a list containing `A` and `C`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
len(graph["B"]) == 2 and "A" in graph["B"] and "C" in graph["B"]
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["C"]` should be a list.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
type(graph["C"]) is list
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["C"]` should be a list containing `B` and `D`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
len(graph["C"]) == 2 and "B" in graph["C"] and "D" in graph["C"]
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["D"]` should be a list.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
type(graph["D"]) is list
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["D"]` should be a list containing `A` and `C`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
len(graph["D"]) == 2 and "A" in graph["D"] and "C" in graph["D"]
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
my_graph = {
|
||||
'A': 'B',
|
||||
'B': ['A', 'C'],
|
||||
'C': 'B'
|
||||
}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,74 @@
|
||||
---
|
||||
id: 655771d889132f9ccd341060
|
||||
title: Step 15
|
||||
challengeType: 20
|
||||
dashedName: step-15
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
A graph is called a *weighted* graph when its edges are associated with weights, representing a distance, time or other.
|
||||
|
||||
In your case, these weights will be the distances between each node, or point in space.
|
||||
To represent a weighted graph you can modify your dictionary, using a list of tuples for each value.
|
||||
|
||||
The first element in the tuple will be the connected node, and the second element will be an integer number indicating the distance.
|
||||
|
||||
Modify `my_graph["A"]` into a list of tuples, considering the following distances:
|
||||
|
||||
| Edge | Weight |
|
||||
|------|--------|
|
||||
| A-B | 3 |
|
||||
| B-C | 4 |
|
||||
| C-D | 7 |
|
||||
| D-A | 1 |
|
||||
|
||||
# --hints--
|
||||
|
||||
Your dictionary should have 4 keys called `A`, `B`, `C`, and `D`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
key_list = ["A", "B", "C", "D"]
|
||||
len(graph) == 4 and all(key in graph for key in key_list)
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["A"]` should be a list of tuples.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
type(graph["A"]) is list and all(type(i) is tuple for i in graph["A"])
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["A"]` should be a list of tuples where the first item in the tuple is the connected node and the second item is the distance.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
tuples = [("B", 3), ("D", 1)]
|
||||
len(graph["A"]) == 2 and all(t in graph["A"] for t in tuples)
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
my_graph = {
|
||||
'A': ['B', 'D'],
|
||||
--fcc-editable-region--
|
||||
'B': ['A', 'C'],
|
||||
'C': ['B', 'D'],
|
||||
'D': ['A', 'C']
|
||||
}
|
||||
|
||||
```
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
id: 65577236b056379d5dbc7000
|
||||
title: Step 18
|
||||
challengeType: 20
|
||||
dashedName: step-18
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now you are going to start developing the algorithm to calculate the shortest path between each node in your new graph.
|
||||
|
||||
Declare an empty function called `shortest_path` and don't forget the `pass` keyword.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a `shortest_path` function.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
import inspect
|
||||
f = __locals.get("shortest_path")
|
||||
inspect.isfunction(f)
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
id: 655773b0591c5f9f4045883e
|
||||
title: Step 19
|
||||
challengeType: 20
|
||||
dashedName: step-19
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The algorithm will start at a specified node. Then it will explore the graph to find the shortest path between the starting node, or *source*, and all the other nodes.
|
||||
|
||||
For that your function needs two parameters: `graph`, and `start`. Add them to your function declaration.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your function should accept `graph` and `start` as the parameters, in this order.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
import inspect
|
||||
f = __locals.get("shortest_path")
|
||||
sig = str(inspect.signature(f))
|
||||
sig == '(graph, start)'
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path():
|
||||
pass
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
id: 655773f8b8b5db9fc6d0ae76
|
||||
title: Step 20
|
||||
challengeType: 20
|
||||
dashedName: step-20
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
To keep track of the visited nodes, you need a list of all the nodes in the graph. Once a node is visited, it will be removed from that list.
|
||||
|
||||
Now, replace the `pass` keyword with a variable named `unvisited` and assign it an empty list.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a variable called `unvisited`.
|
||||
|
||||
```js
|
||||
({ test: () =>
|
||||
{
|
||||
const shortest_path = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest_path;
|
||||
assert(function_body.match(/unvisited\s*=/));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Your `unvisited` variable should be an empty list.
|
||||
|
||||
```js
|
||||
({ test: () =>
|
||||
{
|
||||
const shortest_path = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest_path;
|
||||
assert(function_body.match(/unvisited\s*=\s*\[\s*\]/));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start):
|
||||
pass
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
id: 6557743527cb92a06417ea97
|
||||
title: Step 21
|
||||
challengeType: 20
|
||||
dashedName: step-21
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Create a `for` loop to iterate over your graph, and append each node to the `unvisited` list.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `for` loop to iterate over `graph` inside the `shortest_path` function.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)for\s+(\w+)\s+in\s+graph\s*:/m));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You should append each node to `unvisited` inside your `for` loop.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)for\s+(\w+)\s+in\s+graph\s*:\s*^\1\1unvisited\.append\s*\(\s*\2\s*\)/m));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
unvisited = []
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
id: 6557746aad2844a0cd864e12
|
||||
title: Step 22
|
||||
challengeType: 20
|
||||
dashedName: step-22
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
While the algorithm explores the graph, it should keep track of the currently known shortest distance between the starting node and the other nodes.
|
||||
|
||||
Before your `for` loop, create a new variable named `distances` and assign it an empty dictionary.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a `distances` variable.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)distances\s*=.*(?=^\1for.*:)/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Your `distances` variable should be an empty dictionary.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)distances\s*=\s*\{\s*\}.*(?=^\1for.*:)/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
unvisited = []
|
||||
for node in graph:
|
||||
unvisited.append(node)
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,57 @@
|
||||
---
|
||||
id: 655774955b097ea14897db12
|
||||
title: Step 23
|
||||
challengeType: 20
|
||||
dashedName: step-23
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The distance from the starting node is zero, because the algorithm begins its assessment right from there.
|
||||
|
||||
After appending `node` to `unvisited` in your loop, create an `if` statement that triggers if the node is equal to the starting node. Then assign `0` to that node inside the `distances` dictionary.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create an `if` statement that executes when `node` is equal to `start`.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)for.*:.*^\1\1if\s+node\s*==\s*start\s*:/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Inside your new `if` statement you should assign `0` to the node in the `distances` dictionary.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)for.*:.*^\1\1if\s+node\s*==\s*start\s*:\s*^\1\1\1distances\s*\[\s*node\s*\]\s*=\s*0/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
unvisited = []
|
||||
distances = {}
|
||||
for node in graph:
|
||||
unvisited.append(node)
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
id: 655774d01daeeaa1978b99d5
|
||||
title: Step 24
|
||||
challengeType: 20
|
||||
dashedName: step-24
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
At the beginning, all the other nodes in the graph are considered to be at infinite distance from the source node, because the distance has not been determined yet.
|
||||
|
||||
Create an `else` clause and assign an infinite value to the node in the `distances` dictionary. For that, use the `float()` function with the string `inf` as argument to generate a floating point number representing the positive infinity.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `else` clause.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)if.*:.*^\1else\s*:/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You should assign `float('inf')` to `distances[node]` inside your new `else` clause.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)if.*:.*^\1else\s*:\s*^\1\s{4}distances\s*\[\s*node\s*\]\s*=\s*float\s*\(\s*("|')inf\2\s*\)/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
unvisited = []
|
||||
distances = {}
|
||||
for node in graph:
|
||||
unvisited.append(node)
|
||||
if node == start:
|
||||
distances[node] = 0
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
id: 655775221059f5a20493d5d7
|
||||
title: Step 25
|
||||
challengeType: 20
|
||||
dashedName: step-25
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
After your `for` loop, add a `print()` call and pass in the following string to see the values of the variables you have created: `f'Unvisited: {unvisited}\nDistances: {distances}'`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should print `f'Unvisited: {unvisited}\nDistances: {distances}'` after your `for` loop.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/(^\s*)for.*:.*^\1print\s*\(\s*f("|')Unvisited:\s*\{\s*unvisited\s*\}\\nDistances:\s\{\s*distances\s*\}\2\s*\)/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
unvisited = []
|
||||
distances = {}
|
||||
for node in graph:
|
||||
unvisited.append(node)
|
||||
if node == start:
|
||||
distances[node] = 0
|
||||
else:
|
||||
distances[node] = float('inf')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
id: 655776db1eeae0a620e42a0d
|
||||
title: Step 26
|
||||
challengeType: 20
|
||||
dashedName: step-26
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now, call your function passing `my_graph` and `'A'` as the arguments.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call `shortest_path` passing `my_graph` and `'A'` as the arguments.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^shortest_path\s*\(\s*my_graph\s*,\s*("|')A\1\s*\)/m) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
unvisited = []
|
||||
distances = {}
|
||||
for node in graph:
|
||||
unvisited.append(node)
|
||||
if node == start:
|
||||
distances[node] = 0
|
||||
else:
|
||||
distances[node] = float('inf')
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
id: 655777060d8ddea6741be1b1
|
||||
title: Step 27
|
||||
challengeType: 20
|
||||
dashedName: step-27
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
All the distances in `distances` are set to infinite, except for the starting node. The `unvisited` list contains all the nodes in your graph. But actually, you don't need that `for` loop to achieve this result.
|
||||
|
||||
Remove your `for` loop with its entire body.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should remove your `for` loop and all the nested code.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/(^\s*)distances\s*=\s*\{\s*\}\s*\1print\s*\(\s*f("|')Unvisited:\s*\{\s*unvisited\s*\}\\nDistances:\s\{\s*distances\s*\}\2\s*\)/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
unvisited = []
|
||||
distances = {}
|
||||
for node in graph:
|
||||
unvisited.append(node)
|
||||
if node == start:
|
||||
distances[node] = 0
|
||||
else:
|
||||
distances[node] = float('inf')
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}')
|
||||
|
||||
shortest_path(my_graph, 'A')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
id: 65577739f57ecca6c39bb4e9
|
||||
title: Step 28
|
||||
challengeType: 20
|
||||
dashedName: step-28
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The `list()` type constructor enables you to build a list from an iterable.
|
||||
|
||||
Modify the assignment of your `unvisited` variable to use `list()`, and pass `graph` as the iterable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `list()` to generate a list from the `graph` dictionary.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/list\s*\(\s*graph\s*\)/));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You should assign `list(graph)` to `unvisited`.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/unvisited\s*=\s*list\s*\(\s*graph\s*\)/));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
unvisited = []
|
||||
distances = {}
|
||||
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}')
|
||||
|
||||
shortest_path(my_graph, 'A')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
id: 65577791ad8c26a7705e2919
|
||||
title: Step 29
|
||||
challengeType: 20
|
||||
dashedName: step-29
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
With a dictionary comprehension, you can create a dictionary starting from an existing dictionary:
|
||||
|
||||
```py
|
||||
{key: val for key in dict}
|
||||
```
|
||||
|
||||
You want to keep track of the paths between the starting node and each other node.
|
||||
|
||||
After the `distances` variable, create a `paths` variable and assign it a dictionary with all the keys from `graph`. Assign an empty list to each key and use a dictionary comprehension to build your dictionary.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a `paths` variable.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^\s{4}paths\s*\=/m));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Your `paths` variable should use the dictionary comprehension syntax to assign an empty list to each node in graph.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^\s{4}paths\s*\=\s*\{\s*(\w+)\s*:\s*\[\s*\]\s+for\s+\1\s+in\s+graph\s*\}/m));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {}
|
||||
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}')
|
||||
|
||||
shortest_path(my_graph, 'A')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
id: 65577a17564ce8a8e06c1460
|
||||
title: Step 30
|
||||
challengeType: 20
|
||||
dashedName: step-30
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Dictionary comprehensions support conditional `if`/`else` syntax too:
|
||||
|
||||
```py
|
||||
{key: val_1 if condition else val_2 for key in dict}
|
||||
```
|
||||
|
||||
Use a dictionary comprehension to create a dictionary based in `graph` and assign it to the `distances` variable. Give the key a value of zero if the node is equal to the starting node, and infinite otherwise. Use `float('inf')` to achieve the latter.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the dictionary comprehension syntax to give a value to your `distances` variable.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^\s{4}distances\s*=\s*\{\s*(\w+)\s*:\s*0\s+if\s+\1\s*==\s*start\s+else\s+float\s*\(\s*("|')inf\2\s*\)\s+for\s+\1\s+in\s+graph\s*\}/m));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {}
|
||||
paths = {node: [] for node in graph}
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}')
|
||||
|
||||
shortest_path(my_graph, 'A')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
id: 65578c17d54dfab65cd54b95
|
||||
title: Step 31
|
||||
challengeType: 20
|
||||
dashedName: step-31
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Since the algorithm begins its assessment from the starting node, after creating the `paths` dictionary, you need to add the starting node to its own list in the `paths` dictionary.
|
||||
|
||||
Use the `append()` method to append `start` to the `paths[start]` list.
|
||||
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the `append()` method to append `start` to `paths[start]`.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^\s{4}paths\s*\[\s*start\s*\]\.append\s*\(\s*start\s*\)/m));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}')
|
||||
|
||||
shortest_path(my_graph, 'A')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
id: 65578c74607d40b6d8c4757f
|
||||
title: Step 32
|
||||
challengeType: 20
|
||||
dashedName: step-32
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Add `\nPaths: {paths}` at the end of the f-string passed to the `print` call, so that it prints the `paths` variable, too.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should modify your existing `print` call by adding `\nPaths: {paths}` at the end of the f-string.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^\s{4}print\s*\(\s*f("|')Unvisited:\s*\{\s*unvisited\s*\}\\nDistances:\s\{\s*distances\s*\}\\nPaths:\s\{\s*paths\s*\}\1\s*\)/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}')
|
||||
|
||||
shortest_path(my_graph, 'A')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: 65578cb031cd93b77a285db2
|
||||
title: Step 33
|
||||
challengeType: 20
|
||||
dashedName: step-33
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Your function is going to explore all the nodes connected to the starting node. It will calculate the shortest paths for all of them. Then, it will remove the starting node from the unvisited nodes.
|
||||
|
||||
Next, the closest neighbor node will be visited and the process will be repeated until all the nodes are visited.
|
||||
|
||||
From now on, you are going to work on the main loop that explores the nodes in the graph. To avoid issues with running an infinite loop during the algorithm development, turn your function call into a comment.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should turn your function call into a comment.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /#\s*shortest_path\s*\(\s*my_graph\s*,\s*("|')A\1\s*\)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
shortest_path(my_graph, 'A')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
id: 65578cee7f2cb8b80127cce2
|
||||
title: Step 34
|
||||
challengeType: 20
|
||||
dashedName: step-34
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Before the `print` call, create a `while` loop that runs while `unvisited` is not empty. Use the `pass` keyword to fill the loop body.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a `while` loop that executes while `unvisited` is not empty. Don't forget the `pass` keyword.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s{4})while\s+unvisited\s*:\s*^\1\1pass(?=\s*^\1print)/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
#shortest_path(my_graph, 'A')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
id: 65578d0f6c78a0b868a43b9c
|
||||
title: Step 35
|
||||
challengeType: 20
|
||||
dashedName: step-35
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Inside the `while` loop, the first thing to do is define the current node to visit. For that you can use the `min()` function. It returns the smallest item from the iterable passed as the argument.
|
||||
|
||||
Remove `pass`, then create a variable called `current` and assign it `min(unvisited)`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `current` variable in your `while` loop.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s{4})while\s+unvisited\s*:\s*^\1\1current\s*=/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You should assign `min(unvisited)` to your `current` variable.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s{4})while\s+unvisited\s*:\s*^\1\1current\s*=\s*min\s*\(\s*unvisited\s*\)/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
--fcc-editable-region--
|
||||
while unvisited:
|
||||
pass
|
||||
--fcc-editable-region--
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
#shortest_path(my_graph, 'A')
|
||||
|
||||
```
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
id: 65578d4fc3afc3b8f554c882
|
||||
title: Step 36
|
||||
challengeType: 20
|
||||
dashedName: step-36
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
`min()` takes also a keyword-only argument. Passing a function as an additional argument to `min()`, you can modify the way the list items are compared.
|
||||
|
||||
The result of the line you've just written in the previous step is the node that comes first in alphabetical order. Instead you want to select the unvisited node having the smallest distance from the starting node.
|
||||
|
||||
Pass `key=distances.get` as the second argument to your `min()` call. In this way, the comparison will take place depending on the value each `unvisited` list item has inside the `distances` dictionary.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should pass `key=distances.get` as the second argument to your `min()` call.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s{4})while\s+unvisited\s*:\s*^\1\1current\s*=\s*min\s*\(\s*unvisited\s*,\s*key\s*=\s*distances\.get\s*\)/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
--fcc-editable-region--
|
||||
while unvisited:
|
||||
current = min(unvisited)
|
||||
--fcc-editable-region--
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
#shortest_path(my_graph, 'A')
|
||||
|
||||
```
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
id: 65578f895f2a65ba7a916804
|
||||
title: Step 37
|
||||
challengeType: 20
|
||||
dashedName: step-37
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
After the `current` variable assignment, create a `for` loop to iterate over the tuples in the `graph[current]` list. You will need two iterating variables for that.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `for` loop to iterate over the tuples items in the `graph[current]` list. Use two iterating variables and don't forget to add the `pass` keyword.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)while\s+unvisited\s*:.*^\1\1for\s+\w+\s*,\s*\w+\s+in\s+graph\s*\[\s*current\s*\]\s*:\s*^\1\1\1pass/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
--fcc-editable-region--
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
--fcc-editable-region--
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
#shortest_path(my_graph, 'A')
|
||||
|
||||
```
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
id: 65578fcf00322dbad5dee05b
|
||||
title: Step 38
|
||||
challengeType: 20
|
||||
dashedName: step-38
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Create an `if` statement to check if the distance of the neighbor node (the second item in the processed tuple) plus the distance of `current` is less than the currently known distance of the neighbor node (the first item in the processed tuple).
|
||||
|
||||
Use the `pass` keyword to temporarily fill the body of the `if`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `if` statement to check if `distance + distances[current]` is less than `distances[node]`.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)for\s+\w+\s*,\s*\w+\s+in\s+graph\s*\[\s*current\s*\]\s*:\s*^\1(\s{4})if\s+distance\s*\+\s*distances\s*\[\s*current\s*\]\s*<\s*distances\s*\[\s*node\s*\]\s*:/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
--fcc-editable-region--
|
||||
for node, distance in graph[current]:
|
||||
pass
|
||||
--fcc-editable-region--
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
#shortest_path(my_graph, 'A')
|
||||
|
||||
```
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
id: 655790d113d14dbb727eaf41
|
||||
title: Step 40
|
||||
challengeType: 20
|
||||
dashedName: step-40
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Once the distance to a node is set inside the `distances` dictionary, you need to keep track of the path to that node, too. If the distance for the node in the processed tuple has been updated, the last item in its path is the node itself.
|
||||
|
||||
Inside your conditional, nest another `if` statement that triggers when the last element of `paths[node]` is equal to `node`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a nested `if` statements that checks if `paths[node][-1]` is equal to `node`. Don't forget to use `pass`.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)if.*:.*^\1(\s{4})if\s+paths\s*\[\s*node\s*\]\s*\[\s*-\s*1\s*\]\s*==\s*node\s*:\s*^\1\2\2pass/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
--fcc-editable-region--
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
--fcc-editable-region--
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
#shortest_path(my_graph, 'A')
|
||||
```
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
id: 6557910b0ebaeebc18209e90
|
||||
title: Step 41
|
||||
challengeType: 20
|
||||
dashedName: step-41
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now remove `pass` and assign `paths[current]` to `paths[node]`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should delete `pass` and assign `paths[current]` to `paths[node]`.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)if.*:.*^\1(\s{4})if\s+paths\s*\[\s*node\s*\]\s*\[\s*-\s*1\s*\]\s*==\s*node\s*:\s*^\1\2\2paths\s*\[\s*node\s*\]\s*=\s*paths\s*\[\s*current\s*\]/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
--fcc-editable-region--
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
if paths[node][-1] == node:
|
||||
pass
|
||||
--fcc-editable-region--
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
#shortest_path(my_graph, 'A')
|
||||
|
||||
```
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
id: 6557913b8fe5c0bc834c9f4f
|
||||
title: Step 42
|
||||
challengeType: 20
|
||||
dashedName: step-42
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Next, create an `else` statement and use the `extend()` function to add the current node path to the neighbor node path.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create an `else` statement after your nested `if`.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)if\s+paths\s*\[\s*node\s*\]\s*\[\s*-\s*1\s*\]\s*==\s*node\s*:\s*^\1(\s{4})paths\s*\[\s*node\s*\]\s*=\s*paths\s*\[\s*current\s*\]\s*^\1else\s*:/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You should call `extend()` on the neighbour node path passing the current node path as the argument.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)if\s+paths\s*\[\s*node\s*\]\s*\[\s*-\s*1\s*\]\s*==\s*node\s*:\s*^\1(\s{4})paths\s*\[\s*node\s*\]\s*=\s*paths\s*\[\s*current\s*\]\s*^\1else\s*:\s*^\1\2paths\s*\[\s*node\s*\]\.extend\s*\(\s*paths\s*\[\s*current\s*\]\s*\)/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
--fcc-editable-region--
|
||||
if paths[node][-1] == node:
|
||||
paths[node] = paths[current]
|
||||
--fcc-editable-region--
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
#shortest_path(my_graph, 'A')
|
||||
|
||||
```
|
||||
@@ -0,0 +1,57 @@
|
||||
---
|
||||
id: 655791847db8a9bd0b685f40
|
||||
title: Step 43
|
||||
challengeType: 20
|
||||
dashedName: step-43
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Finally, outside the nested conditionals, append the neighbor node to its path.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should append `node` to `paths[node]` just after your `else` statement.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)else\s*:\s*^\1\s{4}paths\s*\[\s*node\s*\]\.extend\s*\(\s*paths\s*\[\s*current\s*\]\s*\)\s*^\1paths\s*\[\s*node\s*\]\.append\s*\(\s*node\s*\)/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
--fcc-editable-region--
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
if paths[node][-1] == node:
|
||||
paths[node] = paths[current]
|
||||
else:
|
||||
paths[node].extend(paths[current])
|
||||
--fcc-editable-region--
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
#shortest_path(my_graph, 'A')
|
||||
|
||||
```
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
id: 655791ae44c182bd92f31caa
|
||||
title: Step 44
|
||||
challengeType: 20
|
||||
dashedName: step-44
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Terminate the `while` loop by removing the current node from the `unvisited` list. Pay attention to the indentation.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the `remove()` function to remove the current node from `unvisited` after your `for` loop.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)for.*:.*^\1unvisited\.remove\s*\(\s*current\s*\)/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
--fcc-editable-region--
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
if paths[node][-1] == node:
|
||||
paths[node] = paths[current]
|
||||
else:
|
||||
paths[node].extend(paths[current])
|
||||
paths[node].append(node)
|
||||
--fcc-editable-region--
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
#shortest_path(my_graph, 'A')
|
||||
|
||||
```
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
id: 655791e6cf5e03be3de73451
|
||||
title: Step 45
|
||||
challengeType: 20
|
||||
dashedName: step-45
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
If you try to uncomment your function call, it won't work. You have a couple of bugs to fix. The first one happens because in the nested `if` you are trying to access that might not exist in your `paths` dictionary. So, you need to be sure that `paths[node]` is not empty before accessing `paths[node][-1]`.
|
||||
|
||||
Add an additional condition to your nested `if` statement to ensure that `paths[node]` is non-empty before accessing `paths[node][-1]`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add `paths[node]` as the first condition to your nested `if` statement. Use the `and` operator to combine your conditions.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/if\s+paths\s*\[\s*node\s*\]\s+and\s+paths\s*\[\s*node\s*\]\s*\[\s*-\s*1\s*\]\s*==\s*node\s*:/));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
--fcc-editable-region--
|
||||
if paths[node][-1] == node:
|
||||
paths[node] = paths[current]
|
||||
--fcc-editable-region--
|
||||
else:
|
||||
paths[node].extend(paths[current])
|
||||
paths[node].append(node)
|
||||
unvisited.remove(current)
|
||||
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
#shortest_path(my_graph, 'A')
|
||||
|
||||
```
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
id: 65579228c669fcbebffd01d5
|
||||
title: Step 47
|
||||
challengeType: 20
|
||||
dashedName: step-47
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The other bug is subtle. When a shorter distance is found for a neighbor node, `paths[current]` gets assigned to the neighbor node path, `paths[node]`.
|
||||
|
||||
This means both variables point to the same list. Since lists are mutable, when you append the neighbor node to its path, both `paths[node]` and `paths[current]` are modified because they are the same list. This results in wrong paths, although the distances are correct.
|
||||
|
||||
Fix that bug by assigning a copy of `paths[current]` to the neighbor node path. Modify the existing assignment inside your `if` block.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the slice syntax to assign a copy of `paths[current]` to the neighbor node path.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^(\s*)if\s+paths\s*\[\s*node\s*\]\s+and\s+paths\s*\[\s*node\s*\]\s*\[\s*-\s*1\s*\]\s*==\s*node\s*:\s*^\1\s{4}paths\s*\[\s*node\s*\]\s*=\s*paths\s*\[\s*current\s*\]\s*\[\s*::?\s*\]/ms) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
--fcc-editable-region--
|
||||
if paths[node] and paths[node][-1] == node:
|
||||
paths[node] = paths[current]
|
||||
--fcc-editable-region--
|
||||
else:
|
||||
paths[node].extend(paths[current])
|
||||
paths[node].append(node)
|
||||
unvisited.remove(current)
|
||||
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
shortest_path(my_graph, 'A')
|
||||
|
||||
```
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
id: 6557924d47c325bf27afbe51
|
||||
title: Step 48
|
||||
challengeType: 20
|
||||
dashedName: step-48
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The algorithm is complete but you can improve the output. Also, you can provide the function with an additional argument to return only the path between two nodes.
|
||||
|
||||
Add `target` as the third parameter to your function declaration and give it the default value of an empty string.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your function should take three parameters:`graph`, `start`, and `target`. The order matters.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^def\s+shortest_path\s*\(\s*graph\s*,\s*start\s*,\s*target\s*=?\s*.*\s*\)\s*:/m) })
|
||||
```
|
||||
|
||||
The `target` parameter should have the default value of an empty string.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
import inspect
|
||||
foo = __locals.get("shortest_path")
|
||||
sig = str(inspect.signature(foo))
|
||||
sig == "(graph, start, target='')"
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start):
|
||||
--fcc-editable-region--
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
if paths[node] and paths[node][-1] == node:
|
||||
paths[node] = paths[current][:]
|
||||
else:
|
||||
paths[node].extend(paths[current])
|
||||
paths[node].append(node)
|
||||
unvisited.remove(current)
|
||||
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
shortest_path(my_graph, 'A')
|
||||
|
||||
```
|
||||
@@ -0,0 +1,72 @@
|
||||
---
|
||||
id: 6557927ad11e58bf8c794b25
|
||||
title: Step 50
|
||||
challengeType: 20
|
||||
dashedName: step-50
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Create a `for` loop to iterate over `targets_to_print` and print the following f-string: `f'\n{start}-{node} distance: {distances[node]}\nPath: {" -> ".join(paths[node])}'`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `for` loop to iterate over `targets_to_print`. Use `node` as iteration variable.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s{4})for\s+node\s+in\s+targets_to_print\s*:/m));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You should print the provided string inside your new `for` loop.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s{4})for\s+node\s+in\s+targets_to_print\s*:\s*^\1\1print\s*\(f("|')\\n\{\s*start\s*\}-\{\s*node\s*\}\sdistance:\s\{\s*distances\s*\[\s*node\s*\]\s*\}\\nPath:\s\{\s*(?=[^\1])("|')\s->\s\3\.join\s*\(\s*paths\s*\[\s*node\s*\]\s*\)\s*\}\2\s*\)/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start, target = ''):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
if paths[node] and paths[node][-1] == node:
|
||||
paths[node] = paths[current][:]
|
||||
else:
|
||||
paths[node].extend(paths[current])
|
||||
paths[node].append(node)
|
||||
unvisited.remove(current)
|
||||
--fcc-editable-region--
|
||||
targets_to_print = [target] if target else graph
|
||||
|
||||
|
||||
shortest_path(my_graph, 'A')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
id: 6559d70c5161b16ff1d6530d
|
||||
title: Step 49
|
||||
challengeType: 20
|
||||
dashedName: step-49
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Python provides a concise way to write `if`/`else` conditionals by using the ternary syntax:
|
||||
|
||||
```py
|
||||
val_1 if condition else val_2
|
||||
```
|
||||
|
||||
The expression above evaluates to `val_1` if `condition` is true, otherwise to `val_2`.
|
||||
|
||||
Delete your `print` call and create a variable called `targets_to_print` after your `while` loop. Use the ternary syntax to assign it `[target]` when `target` is truthy, and `graph` otherwise.
|
||||
|
||||
|
||||
# --hints--
|
||||
|
||||
You should delete your `print` call.
|
||||
|
||||
```js
|
||||
({ test: () => assert.isFalse( /print\s*\(\s*f("|')Unvisited:\s*\{\s*unvisited\s*\}\\nDistances:\s\{\s*distances\s*\}\\nPaths:\s\{\s*paths\s*\}\1\s*\)/.test(code)) })
|
||||
```
|
||||
|
||||
You should create a variable called `targets_to_print` after your `while` loop.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/unvisited\.remove\(current\).*^\s{4}targets_to_print\s*=/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You should the ternary syntax to assign `[target]` when `target` is truthy, and `graph` otherwise to your `targets_to_print` variable.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/unvisited\.remove\(current\).*^\s{4}targets_to_print\s*=\s*\[\s*target\s*\]\s+if\s+target\s+else\s+graph/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start, target = ''):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
if paths[node] and paths[node][-1] == node:
|
||||
paths[node] = paths[current][:]
|
||||
else:
|
||||
paths[node].extend(paths[current])
|
||||
paths[node].append(node)
|
||||
unvisited.remove(current)
|
||||
--fcc-editable-region--
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
shortest_path(my_graph, 'A')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
id: 6559d86fe1b8947954b9178d
|
||||
title: Step 51
|
||||
challengeType: 20
|
||||
dashedName: step-51
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now it's better but you don't want to print the details about the starting node.
|
||||
|
||||
Before the `print` call, add an `if` statement to execute when `node` is equal to `start` and use the `continue` keyword to go to the next loop iteration.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should nest an `if` statement to check that `node` is equal to `start` inside your `for` loop.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s{4})for\s+node\s+in\s+targets_to_print\s*:\s*^\1\1if\s+(node\s*==\s*start|start\s*==\s*node)\s*:/m));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You should use the `continue` keyword to go to the next iteration inside your new `if` statement.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s{4})for\s+node\s+in\s+targets_to_print\s*:\s*^\1\1if\s+(node\s*==\s*start|start\s*==\s*node)\s*:\s*^\1\1\1continue/m));
|
||||
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start, target = ''):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
if paths[node] and paths[node][-1] == node:
|
||||
paths[node] = paths[current][:]
|
||||
else:
|
||||
paths[node].extend(paths[current])
|
||||
paths[node].append(node)
|
||||
unvisited.remove(current)
|
||||
--fcc-editable-region--
|
||||
targets_to_print = [target] if target else graph
|
||||
for node in targets_to_print:
|
||||
print(f'\n{start}-{node} distance: {distances[node]}\nPath: {" -> ".join(paths[node])}')
|
||||
|
||||
shortest_path(my_graph, 'A')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
id: 6559da1b7d75f088f5e6b89f
|
||||
title: Step 52
|
||||
challengeType: 20
|
||||
dashedName: step-52
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Finally, at the very end of your function, return `distances` and `paths`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should return `distances` and `paths` at the bottom of your function.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^\s{4}return\s+distances\s*,\s*paths/m));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start, target = ''):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
if paths[node] and paths[node][-1] == node:
|
||||
paths[node] = paths[current][:]
|
||||
else:
|
||||
paths[node].extend(paths[current])
|
||||
paths[node].append(node)
|
||||
unvisited.remove(current)
|
||||
--fcc-editable-region--
|
||||
targets_to_print = [target] if target else graph
|
||||
for node in targets_to_print:
|
||||
if node == start:
|
||||
continue
|
||||
print(f'\n{start}-{node} distance: {distances[node]}\nPath: {" -> ".join(paths[node])}')
|
||||
|
||||
|
||||
shortest_path(my_graph, 'A')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
id: 6559da93115de78dbbdc7ba3
|
||||
title: Step 54
|
||||
challengeType: 20
|
||||
dashedName: step-54
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
As a final step, modify your function call passing `F` as the third argument and check the output.
|
||||
|
||||
With that, the shortest path algorithm is complete.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call `shortest_path` passing `my_graph`, `'A'` and `'F'` as the arguments.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^shortest_path\s*\(\s*my_graph\s*,\s*("|')A\1\s*,\s*("|')F\2\s*\)/m) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
my_graph = {
|
||||
'A': [('B', 5), ('C', 3), ('E', 11)],
|
||||
'B': [('A', 5), ('C', 1), ('F', 2)],
|
||||
'C': [('A', 3), ('B', 1), ('D', 1), ('E', 5)],
|
||||
'D': [('C',1 ), ('E', 9), ('F', 3)],
|
||||
'E': [('A', 11), ('C', 5), ('D', 9)],
|
||||
'F': [('B', 2), ('D', 3)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start, target = ''):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
if paths[node] and paths[node][-1] == node:
|
||||
paths[node] = paths[current][:]
|
||||
else:
|
||||
paths[node].extend(paths[current])
|
||||
paths[node].append(node)
|
||||
unvisited.remove(current)
|
||||
|
||||
targets_to_print = [target] if target else graph
|
||||
for node in targets_to_print:
|
||||
if node == start:
|
||||
continue
|
||||
print(f'\n{start}-{node} distance: {distances[node]}\nPath: {" -> ".join(paths[node])}')
|
||||
|
||||
return distances, paths
|
||||
|
||||
shortest_path(my_graph, 'A')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 5), ('C', 3), ('E', 11)],
|
||||
'B': [('A', 5), ('C', 1), ('F', 2)],
|
||||
'C': [('A', 3), ('B', 1), ('D', 1), ('E', 5)],
|
||||
'D': [('C',1 ), ('E', 9), ('F', 3)],
|
||||
'E': [('A', 11), ('C', 5), ('D', 9)],
|
||||
'F': [('B', 2), ('D', 3)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start, target = ''):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
if paths[node] and paths[node][-1] == node:
|
||||
paths[node] = paths[current][:]
|
||||
else:
|
||||
paths[node].extend(paths[current])
|
||||
paths[node].append(node)
|
||||
unvisited.remove(current)
|
||||
|
||||
targets_to_print = [target] if target else graph
|
||||
for node in targets_to_print:
|
||||
if node == start:
|
||||
continue
|
||||
print(f'\n{start}-{node} distance: {distances[node]}\nPath: {" -> ".join(paths[node])}')
|
||||
|
||||
return distances, paths
|
||||
|
||||
shortest_path(my_graph, 'A', 'F')
|
||||
|
||||
```
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
id: 6566195b0a021bb660b2b4b1
|
||||
title: Step 16
|
||||
challengeType: 20
|
||||
dashedName: step-16
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now modify `my_graph["B"]` into a list of tuples. The `B-C` distance is `4`.
|
||||
|
||||
# --hints--
|
||||
|
||||
`my_graph["B"]` should be a list of tuples.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
type(graph["B"]) is list and all(type(i) is tuple for i in graph["B"])
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["B"]` should be a list of tuples where the first item in the tuple is the connected node and the second item is the distance.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
tuples = [("A", 3), ("C", 4)]
|
||||
len(graph["B"]) == 2 and all(t in graph["B"] for t in tuples)
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': ['A', 'C'],
|
||||
--fcc-editable-region--
|
||||
'C': ['B', 'D'],
|
||||
'D': ['A', 'C']
|
||||
}
|
||||
|
||||
```
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
id: 65661b72d6745ebec6a96923
|
||||
title: Step 17
|
||||
challengeType: 20
|
||||
dashedName: step-17
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In the same way, modify the remaining two lists considering that the `C-D` distance is `7`.
|
||||
|
||||
# --hints--
|
||||
|
||||
`my_graph["C"]` should be a list of tuples.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
type(graph["C"]) is list and all(type(i) is tuple for i in graph["C"])
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["C"]` should be a list of tuples where the first item in the tuple is the connected node and the second item is the distance.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
tuples = [("B", 4), ("D", 7)]
|
||||
len(graph["C"]) == 2 and all(t in graph["C"] for t in tuples)
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["D"]` should be a list of tuples.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
type(graph["D"]) is list and all(type(i) is tuple for i in graph["D"])
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
`my_graph["D"]` should be a list of tuples where the first item in the tuple is the connected node and the second item is the distance.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
tuples = [("A", 1), ("C", 7)]
|
||||
len(graph["D"]) == 2 and all(t in graph["D"] for t in tuples)
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': ['B', 'D'],
|
||||
'D': ['A', 'C']
|
||||
}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
id: 6567722f53ad97d7ea6bb082
|
||||
title: Step 46
|
||||
challengeType: 20
|
||||
dashedName: step-46
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now uncomment your function call.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should restore your `shortest_path(my_graph, 'A')` call.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^shortest_path\s*\(\s*my_graph\s*,\s*("|')A\1\s*\)/m) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
--fcc-editable-region--
|
||||
if paths[node] and paths[node][-1] == node:
|
||||
paths[node] = paths[current]
|
||||
|
||||
else:
|
||||
paths[node].extend(paths[current])
|
||||
paths[node].append(node)
|
||||
unvisited.remove(current)
|
||||
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
#shortest_path(my_graph, 'A')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
id: 65774ae7c3eee66fe79b9459
|
||||
title: Step 53
|
||||
challengeType: 20
|
||||
dashedName: step-53
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now, you are going to test your function with another graph. Change `my_graph` into the following graph:
|
||||
|
||||
```py
|
||||
{
|
||||
'A': [('B', 5), ('C', 3), ('E', 11)],
|
||||
'B': [('A', 5), ('C', 1), ('F', 2)],
|
||||
'C': [('A', 3), ('B', 1), ('D', 1), ('E', 5)],
|
||||
'D': [('C', 1), ('E', 9), ('F', 3)],
|
||||
'E': [('A', 11), ('C', 5), ('D', 9)],
|
||||
'F': [('B', 2), ('D', 3)]
|
||||
}
|
||||
```
|
||||
|
||||
# --hints--
|
||||
|
||||
You should modify `my_graph` into the provided graph.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
graph = __locals.get("my_graph")
|
||||
g = {
|
||||
'A': [('B', 5), ('C', 3), ('E', 11)],
|
||||
'B': [('A', 5), ('C', 1), ('F', 2)],
|
||||
'C': [('A', 3), ('B', 1), ('D', 1), ('E', 5)],
|
||||
'D': [('C',1 ), ('E', 9), ('F', 3)],
|
||||
'E': [('A', 11), ('C', 5), ('D', 9)],
|
||||
'F': [('B', 2), ('D', 3)]
|
||||
}
|
||||
graph == g
|
||||
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
--fcc-editable-region--
|
||||
def shortest_path(graph, start, target = ''):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
if distance + distances[current] < distances[node]:
|
||||
distances[node] = distance + distances[current]
|
||||
if paths[node] and paths[node][-1] == node:
|
||||
paths[node] = paths[current][:]
|
||||
else:
|
||||
paths[node].extend(paths[current])
|
||||
paths[node].append(node)
|
||||
unvisited.remove(current)
|
||||
|
||||
targets_to_print = [target] if target else graph
|
||||
for node in targets_to_print:
|
||||
if node == start:
|
||||
continue
|
||||
print(f'\n{start}-{node} distance: {distances[node]}\nPath: {" -> ".join(paths[node])}')
|
||||
|
||||
return distances, paths
|
||||
shortest_path(my_graph, 'A')
|
||||
|
||||
```
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
id: 657891ab9c1903f4e55433ba
|
||||
title: Step 39
|
||||
challengeType: 20
|
||||
dashedName: step-39
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Inside your new `if` block, delete `pass` and reassign the neighbor node distance to the sum of the neighbor node distance plus the distance of `current`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should assign `distance + distances[current]` to the neighbor node distance inside your new `if`.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const shortest = __helpers.python.getDef(code, "shortest_path");
|
||||
const {function_body} = shortest;
|
||||
assert(function_body.match(/^(\s*)if\s+distance\s*\+\s*distances\s*\[\s*current\s*\]\s*<\s*distances\s*\[\s*node\s*\]\s*:\s*^\1\s{4}distances\s*\[\s*node\s*\]\s*=\s*distance\s*\+\s*distances\s*\[\s*current\s*\]/ms));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
my_graph = {
|
||||
'A': [('B', 3), ('D', 1)],
|
||||
'B': [('A', 3), ('C', 4)],
|
||||
'C': [('B', 4), ('D', 7)],
|
||||
'D': [('A', 1), ('C', 7)]
|
||||
}
|
||||
|
||||
def shortest_path(graph, start):
|
||||
unvisited = list(graph)
|
||||
distances = {node: 0 if node == start else float('inf') for node in graph}
|
||||
paths = {node: [] for node in graph}
|
||||
paths[start].append(start)
|
||||
|
||||
while unvisited:
|
||||
current = min(unvisited, key=distances.get)
|
||||
for node, distance in graph[current]:
|
||||
--fcc-editable-region--
|
||||
if distance + distances[current] < distances[node]:
|
||||
pass
|
||||
--fcc-editable-region--
|
||||
print(f'Unvisited: {unvisited}\nDistances: {distances}\nPaths: {paths}')
|
||||
|
||||
#shortest_path(my_graph, 'A')
|
||||
|
||||
```
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
id: 65789506b30453080f77470c
|
||||
title: Step 1
|
||||
challengeType: 20
|
||||
dashedName: step-1
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
So far, you have already met different data types:
|
||||
|
||||
- Immutable data types, such as integers, strings, tuples, and Booleans.
|
||||
- Mutable data types, such as lists.
|
||||
|
||||
A dictionary is a mutable data type and it is identified by a pair of curly braces, `{}`.
|
||||
|
||||
Start by creating a variable called `copper` and assign it an empty dictionary using a pair of curly braces, in the same way you would create an empty list with a pair of square brackets.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a variable called `copper`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__userGlobals.has("copper")) })
|
||||
```
|
||||
|
||||
Your `copper` variable should have the value of an empty dictionary. Use a pair of curly braces for that.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
copper = __locals.get("copper")
|
||||
copper == {}
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
id: 6578b13757611e2825beb8a5
|
||||
title: Step 3
|
||||
challengeType: 20
|
||||
dashedName: step-3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Keys must be unique whitin a dictionary and they can be only immutable data types. This means you cannot use a list or another dictionary as keys.
|
||||
|
||||
Add another key `age` to your dictionary and give it the integer number `2` as value.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add a new key-value pair to your `copper` dictionary.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
copper = __locals.get("copper")
|
||||
len(copper) == 2
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should have an `age` key with the value `2` just after `'species': 'guinea pig'`, inside your `copper` dictionary. Don't forget the comma.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
copper = __locals.get("copper")
|
||||
copper == {"species": "guinea pig", "age": 2}
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
copper = {'species': 'guinea pig'}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
id: 6578b57361f2f132a02e2a18
|
||||
title: Step 4
|
||||
challengeType: 20
|
||||
dashedName: step-4
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You can access the data stored in a dictionary through its keys:
|
||||
|
||||
```py
|
||||
my_dict = {
|
||||
'name': 'Michael',
|
||||
'occupation': 'Lumberjack`
|
||||
}
|
||||
|
||||
my_dict['name'] # 'Michael'
|
||||
```
|
||||
|
||||
After your dictionary, follow the example above to access the `species` key of `copper` and print the result.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should not modify your dictionary.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
copper = __locals.get("copper")
|
||||
copper == {"species": "guinea pig", "age": 2}
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should use `copper['species']` to access the value of the `species` key.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /copper\s*\[\s*("|')species\1\s*\]/) })
|
||||
```
|
||||
|
||||
You should call `print()` passing `copper['species']` as argument.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^print\s*\(\s*copper\s*\[\s*("|')species\1\s*\]\s*\)/m) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
copper = {
|
||||
'species': 'guinea pig',
|
||||
'age': 2
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
id: 65796fac81f983127558f3f4
|
||||
title: Step 5
|
||||
challengeType: 20
|
||||
dashedName: step-5
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now, modify your existing `print()` call to print the value of the `age` key.
|
||||
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `copper['age']` to access the value of the `age` key.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /copper\s*\[\s*("|')age\1\s*\]/) })
|
||||
```
|
||||
|
||||
You should call `print()` passing `copper['age']` as argument.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^print\(\s*copper\s*\[\s*("|')age\1\s*\]\s*\)/m) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
copper = {
|
||||
'species': 'guinea pig',
|
||||
'age': 2
|
||||
}
|
||||
print(copper['species'])
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
id: 6579717f0920131304286804
|
||||
title: Step 6
|
||||
challengeType: 20
|
||||
dashedName: step-6
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
To add a new key-value pair after declaring a dictionary, you can indicate the key in the same way you would access an existing key, and set the value of the new key by using the assignment operator:
|
||||
|
||||
```py
|
||||
my_dict = {
|
||||
'name': 'Michael',
|
||||
'occupation': 'Lumberjack`
|
||||
}
|
||||
|
||||
my_dict['country'] = 'Canada'
|
||||
```
|
||||
|
||||
Delete your `print()` call. Then, after declaring `copper`, add the key `food` to your dictionary and set its value to `hay`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should not have `print(copper['age'])` in your code.
|
||||
|
||||
```js
|
||||
({ test: () => assert.notMatch(code, /^print\(\s*copper\s*\[\s*("|')age\1\s*\]\s*\)/m) })
|
||||
```
|
||||
|
||||
You should add the key `food` to `copper` after declaring the dictionary.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /copper\s*\[\s*("|')food\1\s*\]/) })
|
||||
```
|
||||
|
||||
You should set `copper['food']` to `hay` after declaring the dictionary.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^copper\s*\[\s*("|')food\1\s*\]\s*=\s*("|')hay\2/m) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
copper = {
|
||||
'species': 'guinea pig',
|
||||
'age': 2
|
||||
}
|
||||
print(copper['age'])
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
id: 65797670e0c0d016f17e7660
|
||||
title: Step 7
|
||||
challengeType: 20
|
||||
dashedName: step-7
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now, at the bottom of your code, print `copper`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should print `copper` at the bottom of your code.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /(?<!\}\s*)^print\s*\(\s*copper\s*\)/m) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
copper = {
|
||||
'species': 'guinea pig',
|
||||
'age': 2
|
||||
}
|
||||
copper['food'] = 'hay'
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: 6579ca0923cfa7162089d2f0
|
||||
title: Step 8
|
||||
challengeType: 20
|
||||
dashedName: step-8
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The same syntax can be used to change the value of an existing key.
|
||||
|
||||
Just before the `print()` call, access the `species` key and reassign its value to `Cavia porcellus`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should reassign the `copper['species']` to the string `Cavia porcellus` before the `print()` call.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^copper\s*\[\s*("|')species\1\s*\]\s*=\s*("|')Cavia porcellus\2.*^print\s*\(\s*copper\s*\)/ms) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
copper = {
|
||||
'species': 'guinea pig',
|
||||
'age': 2
|
||||
}
|
||||
copper['food'] = 'hay'
|
||||
|
||||
print(copper)
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: 6579cbab9825b8170974c69a
|
||||
title: Step 9
|
||||
challengeType: 20
|
||||
dashedName: step-9
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You can remove a key-value pair from a dictionary by using the `del` keyword. The syntax is the following:
|
||||
|
||||
```py
|
||||
my_dict = {
|
||||
'name': 'Michael',
|
||||
'occupation': 'Lumberjack`
|
||||
}
|
||||
|
||||
del my_dict['occupation']
|
||||
```
|
||||
|
||||
Just before your `print()` call, use the `del` keyword to delete the `age` key and its value from `copper`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the `del` keyword to delete `copper['age']` before the `print()` call.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^del\s+copper\[\s*("|')age\1\s*\].*^print\s*\(\s*copper\s*\)/ms) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
copper = {
|
||||
'species': 'guinea pig',
|
||||
'age': 2
|
||||
}
|
||||
copper['food'] = 'hay'
|
||||
copper['species'] = 'Cavia porcellus'
|
||||
|
||||
print(copper)
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
id: 6579cd5f6dd62c189e53ddbb
|
||||
title: Step 10
|
||||
challengeType: 20
|
||||
dashedName: step-10
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that you got the basic aspects of dictionaries, you can proceed to build the shortest path algorithm.
|
||||
|
||||
Delete every line of code after the declaration of the `copper` dictionary.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should delete the lines after the declaration of your dictionary.
|
||||
|
||||
```js
|
||||
({ test: () => assert.isFalse( /copper\s*\[.*?\]|del|print\s*\(.*?\)/ms.test(code)) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
copper = {
|
||||
'species': 'guinea pig',
|
||||
'age': 2
|
||||
}
|
||||
--fcc-editable-region--
|
||||
copper['food'] = 'hay'
|
||||
copper['species'] = 'Cavia porcellus'
|
||||
del copper['age']
|
||||
print(copper)
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: 6579dd49fa8a8e1fd06b85a9
|
||||
title: Step 11
|
||||
challengeType: 20
|
||||
dashedName: step-11
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Graphs are data structures representing relations between pairs of elements.
|
||||
These elements, called *nodes*, can be real-life objects, entities, points in space or others. The connections between the nodes are called the *edges*.
|
||||
|
||||
For example, a graph can be used to represent two points in the space, `A` and `B`, connected by a path. A graph like this will be made of two nodes connected by an edge.
|
||||
|
||||
Rename the `copper` dictionary into `my_graph`. This will represent the graph to test your algorithm.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should rename your `copper` dictionary into `my_graph`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__userGlobals.has("my_graph")) })
|
||||
```
|
||||
|
||||
Your `my_graph` variable should be a dictionary.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
my_graph = __locals.get("my_graph")
|
||||
type(my_graph) is dict
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
copper = {
|
||||
'species': 'guinea pig',
|
||||
'age': 2
|
||||
}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
Reference in New Issue
Block a user