find path and convert from dictionary to list - python

I am using networkx library for Python with BFS and DFS. I need to get a tree and then explore it to get a path from a start node to an end node.
For the BFS part I am using bfs_successorsand it returns an iterator of successors in breadth-first-search from source.
For the DFS part I am using: dfs_successors and it returns a dictionary of successors in depth-first-search from source.
I need to get a list of nodes from source to end from both the algorithms. Each node is (x, y) and is a cell in a grid.
Here's what I've done so far:
BFS = nx.bfs_successors(mazePRIM, start)
print(dict(BFS))
DFS = nx.dfs_successors(mazePRIM, start)
print(DFS)
and I get this:
{(0, 0): [(0, 1), (1, 0)], (1, 0): [(1, 1)], (1, 1): [(1, 2)], (1, 2): [(0, 2), (1, 3)], (0, 2): [(0, 3)]}
{(0, 0): [(0, 1), (1, 0)], (1, 0): [(1, 1)], (1, 1): [(1, 2)], (1, 2): [(0, 2), (1, 3)], (0, 2): [(0, 3)]}
but I need an output like this:
[(0, 0), (1, 0), (1, 1), (1, 2), (1, 3)]
which is the list of nodes from start to end.
Do you have any advice about how to do it? Can you help me please?

Use a list comprehension and imply add .keys() to the end of your dictionaries:
DFS = nx.bfs_successors(mazePRIM,start)
print([n for n in dict(BFS).keys()])
DFS = nx.dfs_successors(mazePRIM, start)
print([n for n in DFS.keys()])
You can read more about dictionary keys here:
How to return dictionary keys as a list in Python?

You can simply convert the dictionary keys directly to a list:
DFS = nx.bfs_successors(mazePRIM,start)
print(list(dict(BFS).keys()))
DFS = nx.dfs_successors(mazePRIM, start)
print(list(dict(DFS).keys()))

Related

Repeat elememts based on another elements in the nested list

I have a nested list e.g., ls=[((0,3),(1,0),(2,2),(3,0)),((0,0),(1,3),(2,2),(3,0))].
And I would like to have the following modified list:
modified_ls=[((0,0),(0,0),(0,0),(1,0),(2,0),(2,0),(3,0)),((0,0),(1,0),(1,0),(1,0),(2,0),(2,0),(3,0))]
There the element (x,0) in modified_ls is repeated by N (N!=0) times which is based on the element (x, N) in ls.
Here is what I do (quite stupid):
ls=[((0,3),(1,0),(2,2),(3,0)),((0,0),(1,3),(2,2),(3,0))]
modified_temp_ls=[]
for ii in ls:
for jj in ii:
temp=jj[1]
if temp==0:
modified_temp_ls.append(jj)
else:
while temp:
modified_temp_ls.append((jj[0],0))
temp-=1
ls2=modified_temp_ls[0:int(len(modified_temp_ls)/2)]
ls3=modified_temp_ls[int(len(modified_temp_ls)/2):int(len(modified_temp_ls))]
modified_ls=[]
modified_ls.append(tuple(ls2))
modified_ls.append(tuple(ls3))
Are there any simple way to do it (e.g, without using ls2 and ls3, etc.)? Thank you very much in advance for any suggestions!
This is just list manipulation. Generate the individual sequences, then use sum to combine them into a single list.
ls=[((0,3),(1,0),(2,2),(3,0)),((0,0),(1,3),(2,2),(3,0))]
accum = []
for k in ls:
accum.append(sum([ [(i,0)]*max(1,n) for i,n in k ],[]))
print(accum)
Output:
[[(0, 0), (0, 0), (0, 0), (1, 0), (2, 0), (2, 0), (3, 0)], [(0, 0), (1, 0), (1, 0), (1, 0), (2, 0), (2, 0), (3, 0)]]
Or for the obligatory one liner:
ls=[((0,3),(1,0),(2,2),(3,0)),((0,0),(1,3),(2,2),(3,0))]
accum = [sum([[(i,0)]*max(1,n) for i,n in k ],[]) for k in ls]

Converting keys from float to int in dict in dict in list in dict

I've a dict data as below. I want to convert the float into integers. How do I go about it? I tried a few ways but to no avail.
data:
data =
{'ABC': {'2020-09-01': [{487.0: (0, 1), 488.0: (1, 2)}, {489.0: (0, 1), 481.0: (1, 2)}]},
'CDE': {'2020-01-01': [{484.0: (0, 1), 483.0: (1, 2)}, {482.0: (0, 1), 481.0: (1, 2)}]}}
I want this:
{'ABC': {'2020-09-01': [{487: (0, 1), 488: (1, 2)}, {489: (0, 1), 481: (1, 2)}]},
'CDE': {'2020-01-01': [{484: (0, 1), 483: (1, 2)}, {482: (0, 1), 481: (1, 2)}]}}
I tried this code, but I get this error "RuntimeError: dictionary keys changed during iteration":
I understand keys are immutable so I googled and found "pop" is an alternative solution
for i in data:
for date in data[i]:
for model in range(0, len(data[i][date])):
for k, v in data[i][date][model].items():
data[i][date][model][int(k)] = data[i][date][model].pop(k)
The problem is that you are tying to modify the dictionary while iterating over the same in:
for k, v in data[i][date][model].items():
data[i][date][model][int(k)] = data[i][date][model].pop(k)
You could consider using list comprehension instead:
for k_l1, v_l1 in data.items(): #iterate first level of dict
for k_l2, v_l2 in v_l1.items(): #iterate second level of dict
data[k_l1][k_l2] = [{ int(key): val for key, val in elt.items() } for elt in v_l2] # update the list
Output:
{'ABC': {'2020-09-01': [{487: (0, 1), 488: (1, 2)}, {489: (0, 1), 481: (1, 2)}]}, 'CDE': {'2020-01-01': [{484: (0, 1), 483: (1, 2)}, {482: (0, 1), 481: (1, 2)}]}}

Find a path between two values in a dictionary in Python

I am trying to find the path between two elements in a dictionary.
Let me explain the situation. Using NetworkX I created a graph and using bfs_successors and dfs_successors I created two trees, saved in two dictionaries, as you can see:
BFS = nx.bfs_successors(mazePRIM, start)
print(dict(BFS))
DFS = nx.dfs_successors(mazePRIM, start)
print(DFS)
and I get this:
{(0, 0): [(0, 1), (1, 0)], (1, 0): [(1, 1)], (1, 1): [(1, 2)], (1, 2): [(0, 2), (1, 3)], (0, 2): [(0, 3)]}
{(0, 0): [(0, 1), (1, 0)], (1, 0): [(1, 1)], (1, 1): [(1, 2)], (1, 2): [(0, 2), (1, 3)], (0, 2): [(0, 3)]}
Now I need to get the "path" between the root/start, (0,0), and an end node, for example (1,3). How can I get it?
So I need a function to search the end node and to return the path between start and end.
And is it possible to write it this way?
[(0, 0), (1, 0), (1, 1), (1, 2), (1, 3)]
Boundary: I need to use dfs and bfs. In fact, as I created the dfs-tree and the bfs-tree, I want to locate one node (which will be the end node) and reconstruct its path.
Thank you in advance
I think the idea of networkx (although I've never used it) is probably that you'd use a function like shortest_path to find the path between two specific nodes, and you'd only use the dfs/bfs functions if you want an exhaustive list of all the reachable nodes.
That said, if you wanted to roll your own DFS using the dictionary you got from those functions, here's an example:
>>> from typing import Dict, List, Tuple
>>>
>>>
>>> def dfs(
... graph: Dict[Tuple[int, int], List[Tuple[int, int]]],
... path: List[Tuple[int, int]],
... target: Tuple[int, int]
... ) -> List[Tuple[int, int]]:
... """Given a graph and a starting path, return the
... complete path through the graph to the target."""
... if path[-1] == target:
... return path
... if path[-1] not in graph:
... return []
... for node in graph[path[-1]]:
... if node in path:
... continue
... maybe_path = dfs(graph, path + [node], target)
... if len(maybe_path):
... return maybe_path
... return []
...
>>>
>>> print(dfs(
... {(0, 0): [(0, 1), (1, 0)], (1, 0): [(1, 1)], (1, 1): [(1, 2)], (1, 2): [(0, 2), (1, 3)], (0, 2): [(0, 3)]},
... [(0, 0)],
... (1, 3)
... ))
[(0, 0), (1, 0), (1, 1), (1, 2), (1, 3)]

Order of For Loops with Python List Comprehension

In this answer, it is claimed that
The best way to remember this is that the order of for loop inside the list comprehension is based on the order in which they appear in traditional loop approach. Outer most loop comes first, and then the inner loops subsequently.
However, this answer,, and my own experiment below, seem to show the opposite - i.e, the inner loop coming first.
In my example, I want j to represent the row number and i to represent the column number. I want 5 rows and 4 columns What am I missing please?
board = [[(j, i) for i in range(4)] for j in range(5)]
# I believe the above comprehension is equivalent to the nested for loops below
# board = []
# for j in range(5):
# new_row = []
# for i in range(4):
# new_row.append((j,i))
# board.append(new_row)
for j in range(5):
for i in range(4):
print(board[j][i], end="")
print()
This is the correct way to get desired output:
board = [(j, i) for i in range(4) for j in range(5)]
Output:-
[(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (0, 2), (1, 2), (2, 2), (3, 2), (4, 2), (0, 3), (1, 3), (2, 3), (3, 3), (4, 3)]

How to put the tuple (i,j) in a list multiple times without using concatenation?

I want to add some tuples (i,j) in a list as many time as they occur in another function. My result right now is [[(0, 0), (0, 0)]], but I want it to be only a single list [(0, 0), (0, 0)]. Is there any way I can do this without using libraries?
list= [[(i,j)]*number_occurences]
print(list)
>>> [[(0, 0), (0, 0)]]
You literally wrote the [[ that you don't want. So, simply don't do that! Write just the one [ instead.
For example:
>>> [(1,2)]*5
[(1, 2), (1, 2), (1, 2), (1, 2), (1, 2)]

Categories

Resources