Reading from file into dictionaries, and strange eval() behaviour - python

Creating dictionaries from file using eval(), or ast.literal_eval() (as suggested by others) yields strange results, and I'm not sure why.
My file, file.txt contains this:
{0 : {1: 6, 1:8}, 1 : {1:11}, 2 : {3: 9}, 3 : {},4 : {5:3},5 : {2: 7, 3:4}}
I read it into a dictionary and print the contents out as such
graph1 = {}
graph1 = ast.literal_eval(open("file.txt").read())
and I get this thing, where the {1:6} is missing.
{0: {1: 8}, 1: {1: 11}, 2: {3: 9}, 3: {}, 4: {5: 3}, 5: {2: 7, 3: 4}}
I change the contents of 'file.txt' to this:
{0: {2: 7, 3: 4}, 1: {1: 11}, 2: {3: 9}, 3: {}, 4: {5: 3}, 5: {2: 7, 3: 4}}
And then the correct contents display!
Then I change the contents of file.txt to this, where I rewrite 1:6 as 2:6
{0 : {2: 6, 1:8}, 1 : {1:11}, 2 : {3: 9}, 3 : {},4 : {5:3},5 : {2: 7, 3:4}}
And this is the output, where {2:6} and {1:8} switch places!
{0: {1: 8, 2: 6}, 1: {1: 11}, 2: {3: 9}, 3: {}, 4: {5: 3}, 5: {2: 7, 3: 4}}
All I want to do is correctly read the contents of a file into my dictionary. What is going wrong?

Dictionaries can not have duplicate key. In case same key is provided to the dict object, former value is overridden by the later value.
For example:
>>> d = {'a': 'x', 'b': 'y', 'c': 'z', 'a': 'w'}
>>> d
{'a': 'w', 'c': 'z', 'b': 'y'} # ('a': 'x') is overridden by ('a': 'w')

The reason of missing 1:6 is because of that you have 1:8 in your dictionary too, and since python use hash table for implementing the dictionaries, they don't preserve duplicate keys (because they have same hash value) and the reason of changing the order is that dictionaries don't have a specific order because of the way they are implemented.

Related

Sort dictionary with attribute value

I have a list dictionary like this: {1: {'a': 5, 'score': 3}, 2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}} and want to sort it using its score attribute.
Intended output: {2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}, 1: {'a': 5, 'score': 3}}
I have trying to use the built-in function to sort the list but its not giving desired output
updatedList = sorted(b, key=lambda k: k['score'])
Any hints how I can get the desired output?
Your data structure is a nested dictionary, not a list.
To sort the dictionary, you can modify your key function to this:
>>> d = {1: {'a': 5, 'score': 3}, 2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}}
>>> dict(sorted(d.items(), key=lambda x: x[1]['score']))
{2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}, 1: {'a': 5, 'score': 3}}
Which converts the original dictionary to dict.items, then uses the score key from the dictionary in the (key, value) tuple. Then after sorting with sorted(), we can convert back to a dictionary with dict().
This works in Python 3.6+ since dictionaries are ordered. If you are using a lower python version, you can maintain dictionary insertion order with collections.OrderedDict instead.
For sorting a Nested Dictionary use the key argument for sorted(). It lets you specify a function that, given the actual item being sorted, returns a value that should be sorted by.
N_Dictionary = {1: {'a': 5, 'score': 3}, 2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}}
s_values = sorted(N_Dictionary.items(), key = lambda x: x[1]["score"] )
s_values

How to add an existing dictionary as a nested dictionary to an already existing dictionary in python?

In python3, I have 2 dictionaries, dict1 and dict2 that are both populated with key/value pairs. I want to create a new dictionary dict3 and add both dict1 and dict2 as nested dictionaries to it. I cant BELIEVE how much time Ive wasted trying to google a solution. I find tutorial after tutorial about how to create nested dictionaries from scratch but nothing about adding an existing dictionary nested to another dictionary.
IIUC:
dict1={1:2,3:4}
dict2={5:6,7:8}
dict3=dict(list(dict1.items())+[('dict2', dict2)])
print(dict3)
Output:
{1: 2, 3: 4, 'dict2': {5: 6, 7: 8}}
Or if you want to add the two dictionary:
dict1={1:2,3:4}
dict2={5:6,7:8}
dict3=dict([('dict1', dict1)]+[('dict2', dict2)])
print(dict3)
#Output:
#{'dict1': {1: 2, 3: 4}, 'dict2': {5: 6, 7: 8}}
Another ways:
#first scenario
dict1={1:2,3:4}
dict2={5:6,7:8}
dict3={**dict1}
dict3.update({'dict2':dict2})
print(dict3)
#Output:
#{1: 2, 3: 4, 'dict2': {5: 6, 7: 8}}
#second scenario
dict1={1:2,3:4}
dict2={5:6,7:8}
dict3={}
dict3.update({'dict1':dict1,'dict2':dict2})
print(dict3)
#Output:
#{'dict1': {1: 2, 3: 4}, 'dict2': {5: 6, 7: 8}}

How to get and modify the value of nested dictionary?

I have this kind of dictionary in python:
x = {'test': {1: 2, 2: 4, 3: 5},
'this': {1: 2, 2: 3, 7: 6},
'is': {1: 2},
'something': {90: 2,92:3}}
I want to modify all of the value in the key by whatever value I want. Let's say 100, the methods I tried are below:
counter = 1
print(x)
for key,anotherKey in x.items():
while counter not in x[key]:
counter+=1
while counter in x[key]:
x[key][counter] = 100
counter+=1
counter =0
Which got the result below:
{'test': {1: 100, 2: 100, 3: 100},
'this': {1: 100, 2: 100, 7: 6},
'is': {1: 100},
'something': {90: 100,92: 3}}
I know why this is happening it's because the loop doesn't consider if the differences is more than 1 which in this case in 'this' : where the differences from 2 to 7 is more than 1. However I don't know how to solve this.
You can iterate via a nested for loop:
x = {'test': {1: 2, 2: 4, 3: 5},
'this': {1: 2, 2: 3, 7: 6},
'is': {1: 2},
'something': {90: 2,92:3}}
for a in x:
for b in x[a]:
x[a][b] = 100
print(x)
{'is': {1: 100},
'something': {90: 100, 92: 100},
'test': {1: 100, 2: 100, 3: 100},
'this': {1: 100, 2: 100, 7: 100}}
Or for a new dictionary you can use a dictionary comprehension:
res = {a: {b: 100 for b in x[a]} for a in x}
You can use dictionary comprehension in this way:
{a: {b:100 for b in d} for (a,d) in x.items()}

How do I find out if a integer variable in python has an out of scope hidden value?

in the code here
How do I force static methods to use local not global variables in Python?
i have a variable that is being passed between methods besides the one in the question. the variable is current_line
def line_tocsv(csv_dict={}, line={}, current_line=0):
csv_line, current_line = LineHandler.create_csv(current_line, kline)
if current_line in csv_dict:
csv_dict[current_line].update(csv_line)
else:
csv_dict[current_line] = csv_line
return csv_dict
when this code is run, it produced an output simmilar to this
>>> a={0:{"aa":1,"bb":"wasd"},1:{"aa":1,"bb":"wasd"}}
>>> a
{0: {'aa': 1, 'bb': 'wasd'}, 1: {'aa': 1, 'bb': 'wasd'}}
>>> a[1].update({"cc":"foo"})
>>> a
{0: {'aa': 1, 'cc': 'foo' 'bb': 'wasd'}, 1: {'aa': 1, 'cc': 'foo', 'bb': 'wasd'}}
how do i make it so that the csv_line dict is only entered into ONE sub dict?!
changing the variable names does not work and i suspect it is because only the references are passed between functions, but i dont know enough python to know where those references actually go and what their order of ops etc is
First, don't use mutable default arguments
def line_tocsv(csv_dict=None, ....):
if not csv_dict:
csv_dict = {}
....
Next, use copy of dict, not pointer:
csv_dict[current_line] = csv_line.copy()
EDIT:
Try to do this:
>>> a
{1: 2, 3: 4}
>>> b = {1:a,2:a}
>>> b
{1: {1: 2, 3: 4}, 2: {1: 2, 3: 4}}
>>> b[1][7] = 8
>>> b
{1: {1: 2, 3: 4, 7: 8}, 2: {1: 2, 3: 4, 7: 8}}
If you want to use value of dict instead of pointer:
>>> a
{1: 2, 3: 4}
>>> b = {1:a.copy(),2:a.copy()}
>>> b
{1: {1: 2, 3: 4}, 2: {1: 2, 3: 4}}
>>> b[1][7] = 8
>>> b
{1: {1: 2, 3: 4, 7: 8}, 2: {1: 2, 3: 4}}

Alternative to deepcopy in python

In a project we have to do for school, we got an assignment to write an implementation for the floyd-warshall algorithm.
One of the restrictions was, that we could not use import statements.
I had not read this and write my algorithm, using deepcopy. Now I am searching for a way to make my own sort of "copy" function.
The thing I want to copy is a dictionary of 2 dictionaries
{"a": {...}, "b": {...}}
Is this possible? thank you very much in advance
You can use a dict comprehension with copy method of dictionary :
d={"a": {...}, "b": {...}}
new={i:j.copy() for i,j in d.items()}
Demo :
>>> d ={1: {1: 5}, 2: {2: 2}, 3: {3: 9}}
>>> l ={i:j.copy() for i,j in d.items()}
>>> l[1][1]=0
>>> l
{1: {1: 0}, 2: {2: 2}, 3: {3: 9}}
>>> d
{1: {1: 5}, 2: {2: 2}, 3: {3: 9}}

Categories