Depth first search current implementation problem when I try to run it - python-3.x

I'm here trying to share my depth first-search (DFS) implementation. I'm trying to learn how can it traverse in a graph that is undirected, meaning that not all nodes are making into one graph, but two different ones. I was looking for the small basics of DFS with one graph only. And I came across to a problem in "what would happen if there are more than one graph and are not connected?" So I started to look around how to do it by using my knowledge from the simple DFS implementation. However, it is a little bit more complicated than I thought. Here is the code sample that I came across:
"""DFS implemention."""
adjacency_matrix = {
1: [2, 3],
2: [4, 5],
3: [5],
4: [6],
5: [6],
6: [7],
7: [],
8: [9],
9: [8]
}
def DFS_un(graph):
"""Traversal for undirected graphs."""
vertices = graph[0]
edges = graph[1]
def visit(vertex):
if vertex in visited:
return
visited.add(vertex)
print(vertex)
if vertex in edges:
for e in edges[vertex]:
visit(e)
visited = {}
for v in vertices:
visit(v)
if __name__ == '__main__':
DFS_un(adjacency_matrix)
And the error message says this:
Traceback (most recent call last):
File "dfs.py", line 33, in <module>
DFS_dis(adjacency_matrix)
File "dfs.py", line 17, in DFS_dis
vertices = graph[0]
KeyError: 0
If you see, I'm using one graph, but it has undirected numbers, which is 8 and 9 (8<->9). Why am I not getting my output correctly? Sorry, learning some Python3 too :). Thanks for your help!

You want:
vertices = graph.keys()
edges = graph.values()
'Graph' is a dictionary object. The graph[0] notation says find me the value associated with the key=0. Since you have no key=0 you get an error.
You might be confusing dictionaries with lists. my_list[0] says get me the value at position 0 in my_list.

I found my problem already. #blueenvelope was right with the idea of the dictionary because there are no KeyWords used and thus giving me 0 for some reason... At the end, it finally reads the whole graph list from unconnected vertices.
My variables vertices and edges were incorrectly implemented and quickly understood it's purpose. Keys is used to find particular dictionaries, so I was pulling keys from the graph vertex. Same goes for my edges, but also pulling the values of those edges from a specific key. Here is the full fixed code:
adjacency_matrix = {
1: [2, 3],
2: [4, 5],
3: [5],
4: [6],
5: [6],
6: [7],
7: [],
8: [9],
9: [8]
}
def DFS_un(graph):
"""Traversal for undirected graphs."""
vertices = graph.keys()
edges = graph.values()
visited = []
def visit(vertex):
if vertex in visited:
return
print("Visited vertex: ")
visited.append(vertex)
print(visited)
print("Current vertex: ")
print(vertex)
print("\n")
if vertex in edges:
for e in edges[vertex]:
visit(e)
for v in vertices:
visit(v)
if __name__ == '__main__':
DFS_un(adjacency_matrix)

Related

Python function removing items form list, dropping unexpected elements

It's a simple code practice challenge that asks that I make a function that takes a list of mixed types and returns only the integers
def return_only_integer(lst):
for i in lst:
if type(i) != int:
lst.remove(i)
return lst
That's it, it seems simple enough but the tests are coming back negative:
return_only_integer([9, 2, "space", "car", "lion", 16])
Returns: [9, 2, 'car', 16]
return_only_integer(["hello", 81, "basketball", 123, "fox"])
Returns what it should: [81, 123]
return_only_integer([10, "121", 56, 20, "car", 3, "lion"])
Also returns what it should: [10, 56, 20, 3]
but:
return_only_integer(["String", True, 3.3, 1])
Returns: [True, 1]
The code is so simple and straightforward, I have no idea why these 2 tests are failing.
Why would 'car' even be in the first list but the other strings not?
type(True) is bool, why is it there?
This is probably due to you modifying the list in the conditional. By removing an item from the list, you are likely shifting the iteration in that operation.
It may be worth looking into filter() instead.
https://docs.python.org/3/library/functions.html#filter
You can create a temporary list inside your function to hold the items that are integers. Once you have processed all the items, you can return the temporary list as part of your return statement. If there are no integers, you can return None.
def return_only_integer(lst):
int_lst = []
for i in lst:
if type(i) == int:
int_lst.append(i)
return int_lst if int_lst else None
print (return_only_integer([9, 2, "space", "car", "lion", 16]))
print (return_only_integer(['ball', True, "space", "car", "lion", 'fish']))
This will output as follows:
[9, 2, 16]
None
def return_only_integer(lst):
for i in lst:
if type(i) != int:
lst.remove(i)
return lst
THIS FUNCTION HAS VERY BIG FAULT.
consider this list [9, 2, "space", "car", "lion", 16]
when it had removed "space" then your i had directly reached to lion and it ignored car because your list is changed and your i index is not changed. so it is moving as it is.
after removing one non integer, you must make sure to change the index position of i. so try this code. it will work.
def return_only_integer(lst):
for i in lst:
#print(i,type(i))
if type(i) != int:
#print("flag this is not integer ",i)
lst.remove(i)
return_only_integer(lst)
return(lst)
print(return_only_integer(["hello", 81, "basketball", 123, "fox"]))
hope u understand. if you didn't understand then tell me .
Indeed you should not change the list you are iterating on, it produces unexpected results. Item deleted leaves room for the next, without the latter being picked in the iteration (so not being dropped in your example).
The possible choices to perform such task involve the usage of another list. A possible solution is very familiar to python developers:
def return_only_integer(lst):
return [i for i in lst if type(i) == int]

Why does shallow copy behaves as deep copy for a simple list

I was going understanding shallow copy and deep copy concepts in python. I observe most of the posts/blogs/SO answer explain these concepts are using a nested lists.
import copy
lst = [[1,2,3],[4,5,6]]
b = copy.copy(lst)
c = copy.deepcopy(lst)
# Shallow copy demo
b[0][0] = 9
print(b)
# >>> [[9, 2, 3], [4, 5, 6]]
print(lst)
# >>> [[9, 2, 3], [4, 5, 6]]
# Deepcopy demo
c[0][0] = 10
print(c)
# >>> [[10, 2, 3], [4, 5, 6]]
print(lst)
# >>> [[9, 2, 3], [4, 5, 6]]
I understood the shallow and deep copy concept with the above simple example. But when I implement the concept, on a simple list (one-dimensional list), the observation is shallow copy behaves as deep copy.
import copy
lst = [1,2,3]
b = copy.copy(lst)
c = copy.deepcopy(lst)
# Shallow copy demo
b[0] = 0
print(b)
# >>> [0, 2, 3]
print(lst)
# >>> [1,2,3]
# Deepcopy demo
c[0] = 9
print(c)
# >>> [9,2,3]
print(lst)
# >>> [1,2,3]
This shows that copy.copy(lst) behaves different and does deep copy instead of shallow copy.
I would like to understand, why the behavior of copy.copy() is different for nested list and simple list. Also if i have to get shallow copy working for simple list, how can i achieve it?.
The results that you're getting are not directly related with the "level of depth", the
most important thing to keep in mind here is the concept of mutabiliy.
List are mutable, meanwhile numeric values are not. That means that you can add or modify items on a list, but those operations doesn't create or destroy the list, they only change it. You can verify that using the built-in function id(), which gives you the memory address of a variable:
lst = [1, 2, 3]
print(id(lst)) # the number printed by this...
lst.append(4)
lst[1] = 0
print(id(lst)) # should be the same printed by this one. That tells us that
# the variable 'lst' keeps referecing the same object, although
# the object have changed in form (mutated)
Numbers are totally different, and it makes sense, since a numeric type variable can only
store a single numeric value:
a = 5
print(id(a)) # the number printed by this...
a = 6
print(id(a)) # should be different than this one, meaning that a new numeric
# value were created and stored in a different memory address
On the line
b[0][0] = 9
of your first example, the list at b[0] is being manipulated, but it remains being the same object, and since b[0] is nothing more than a reference to the same list at lst[0] (because b is a shallow copy), when we print lst we will see that it changed too.
On your implementation, when you assign b[0] = 0, python is creating the value 0, storing it on a new memory location, and overriding the reference that b[0] had to the same value as lst[0] (cause thats the natural behavior of numeric types).
As is said, this doesn't have to be with the level of nesting of compound data structures,
since some of the are inmutable (as for example the tuple) and the same that happened on your implementation would happen with this inmutable data structures.
You can read some more about the id() built-in function here, and more about
mutable and inmutable types here
Hope this answer helps you!

How to assing values to a dictionary

I am creating a function which is supposed to return a dictionary with keys and values from different lists. But I amhavin problems in getting the mean of a list o numbers as values of the dictionary. However, I think I am getting the keys properly.
This is what I get so far:
def exp (magnitudes,measures):
"""return for each magnitude the associated mean of numbers from a list"""
dict_expe = {}
for mag in magnitudes:
dict_expe[mag] = 0
for mea in measures:
summ = 0
for n in mea:
summ += n
dict_expe[mag] = summ/len(mea)
return dict_expe
print(exp(['mag1', 'mag2', 'mag3'], [[1,2,3],[3,4],[5]]))
The output should be:
{mag1 : 2, mag2: 3.5, mag3: 5}
But what I am getting is always 5 as values of all keys. I thought about the zip() method but im trying to avoid it as because the it requieres the same length in both lists.
An average of a sequence is sum(sequence) / len(sequence), so you need to iterate through both magnitudes and measures, calculate these means (arithmetical averages) and store it in a dictionary.
There are much more pythonic ways you can achieve this. All of these examples produce {'mag1': 2.0, 'mag2': 3.5, 'mag3': 5.0} as result.
Using for i in range() loop:
def exp(magnitudes, measures):
means = {}
for i in range(len(magnitudes)):
means[magnitudes[i]] = sum(measures[i]) / len(measures[i])
return means
print(exp(['mag1', 'mag2', 'mag3'], [[1, 2, 3], [3, 4], [5]]))
But if you need both indices and values of a list you can use for i, val in enumerate(sequence) approach which is much more suitable in this case:
def exp(magnitudes, measures):
means = {}
for i, mag in enumerate(magnitudes):
means[mag] = sum(measures[i]) / len(measures[i])
return means
print(exp(['mag1', 'mag2', 'mag3'], [[1, 2, 3], [3, 4], [5]]))
Another problem hides here: i index belongs to magnitudes but we are also getting values from measures using it, this is not a big deal in your case if you have magnitudes and measures the same length but if magnitudes will be larger you will get an IndexError. So it seems to me like using zip function is what would be the best choice here (actually as of python3.6 it doesn't require two lists to be the same length, it will just use the length of shortest one as the length of result):
def exp(magnitudes, measures):
means = {}
for mag, mes in zip(magnitudes, measures):
means[mag] = sum(mes) / len(mes)
return means
print(exp(['mag1', 'mag2', 'mag3'], [[1, 2, 3], [3, 4], [5]]))
So feel free to use the example which suits your requirements of which one you like and don't forget to add docstring.
More likely you don't need such pythonic way but it can be even shorter when dictionary comprehension comes into play:
def exp(magnitudes, measures):
return {mag: sum(mes) / len(mes) for mag, mes in zip(magnitudes, measures)}
print(exp(['mag1', 'mag2', 'mag3'], [[1, 2, 3], [3, 4], [5]]))

finding the keys of all the largest values in python dictionary?

if I have a dictionary
x ={0: 0, 1: 4, 2: 0, 3: 2, 4: 2, 5: 4}
how do i get the keys of all the largest values
In this case they would be 1 and 5 .
Not a duplicate question. looking to find all the keys and not just the one.
x ={0: 0, 1: 4, 2: 0, 3: 2, 4: 2, 5: 4}
maximum = max(x.values())
keys = [key for key, value in x.items() if value == maximum]
print(keys) # => [1, 5]
There is a class in collections called Counter that does exactly what you want. It provides the exact functionality you require via it's most_common method:
from collections import counter
maxes = Counter(x).most_common(2)
print([x[0] for x in maxes])
[1, 5]
Now this is probably not exactly what you want because I hard coded in the number 2. You can get this by using another Counter on the values of your dictionary!
x = Counter(x) # This preserves x: just makes it a subclass of dict
max_count = Counter(x.values())[x.most_common(1)[0][1]]
maxes = x.most_common(max_count)
maxes = [x[0] for x in maxes]
Here, I compute the number of times that the most common value occurs by counting all the different values, and then checking the maximum one using x.most_common(1)[0][1].
Please do not select this answer. #BrightOne has the right answer. This is just a thing I did to see if I could avoid using anything but Counters. It is not actually a good idea.

How do you create a histogram with a list of numbers?

pretend you have a list:
list = [23,25,22,31]
how would you be able to put these numbers into a histogram in python?
Use a default dictionary:
from collections import defaultdict
numbers = [23,25,22,31,23]
histogram = defaultdict(int)
for number in numbers:
histogram[number] += 1
output:
defaultdict(int, {22: 1, 23: 2, 25: 1, 31: 1})
Note: A) Don't call your list "list" since its a reserved word.
B) I made the list of numbers have two 23s to demonstrate a histogram.

Resources