Dictionary with values of empty list - python

I want to create a dictionary with keys of 1, 2, 3, 4
and each value to the key is [].
n = [1,2,3,4]
d = dict.fromkeys(n, [])
d[1].append(777)
print(d)
--> {1: [777], 2: [777], 3: [777], 4: [777]}
Why does this happen? Why is this not {1: [777], 2: [], 3: [], 4: []} ?

The list that you use as values in the second step all point to the same memory. So when you update one of the values, all of them update.
You can check that by using the following -
n = [1,2,3,4]
d = dict.fromkeys(n, [])
d[1] is d[2] #share memory
#True
So, one way you can instead do the following -
n = [1,2,3,4]
d = {k:[] for k in n}
d[1] is d[2]
#False
Then you can set then -
d[1].append(777)
{1: [777], 2: [], 3: [], 4: []}
A better way to do this is to use collections.defaultdict. This allows you to create a dictionary where values are list objects by default using defaultdict(list). Its scalable as you can choose which datatype you need your dictionary values to be.
from collections import defaultdict
n = [1,2,3,4]
d = defaultdict(list)
d[1].append(777)

Related

Method digit - Python [duplicate]

This question already has answers here:
Create a dictionary with comprehension
(17 answers)
Closed last month.
Is it possible to create a dictionary comprehension in Python (for the keys)?
Without list comprehensions, you can use something like this:
l = []
for n in range(1, 11):
l.append(n)
We can shorten this to a list comprehension: l = [n for n in range(1, 11)].
However, say I want to set a dictionary's keys to the same value.
I can do:
d = {}
for n in range(1, 11):
d[n] = True # same value for each
I've tried this:
d = {}
d[i for i in range(1, 11)] = True
However, I get a SyntaxError on the for.
In addition (I don't need this part, but just wondering), can you set a dictionary's keys to a bunch of different values, like this:
d = {}
for n in range(1, 11):
d[n] = n
Is this possible with a dictionary comprehension?
d = {}
d[i for i in range(1, 11)] = [x for x in range(1, 11)]
This also raises a SyntaxError on the for.
There are dictionary comprehensions in Python 2.7+, but they don't work quite the way you're trying. Like a list comprehension, they create a new dictionary; you can't use them to add keys to an existing dictionary. Also, you have to specify the keys and values, although of course you can specify a dummy value if you like.
>>> d = {n: n**2 for n in range(5)}
>>> print d
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
If you want to set them all to True:
>>> d = {n: True for n in range(5)}
>>> print d
{0: True, 1: True, 2: True, 3: True, 4: True}
What you seem to be asking for is a way to set multiple keys at once on an existing dictionary. There's no direct shortcut for that. You can either loop like you already showed, or you could use a dictionary comprehension to create a new dict with the new values, and then do oldDict.update(newDict) to merge the new values into the old dict.
You can use the dict.fromkeys class method ...
>>> dict.fromkeys(range(5), True)
{0: True, 1: True, 2: True, 3: True, 4: True}
This is the fastest way to create a dictionary where all the keys map to the same value.
But do not use this with mutable objects:
d = dict.fromkeys(range(5), [])
# {0: [], 1: [], 2: [], 3: [], 4: []}
d[1].append(2)
# {0: [2], 1: [2], 2: [2], 3: [2], 4: [2]} !!!
If you don't actually need to initialize all the keys, a defaultdict might be useful as well:
from collections import defaultdict
d = defaultdict(True)
To answer the second part, a dict-comprehension is just what you need:
{k: k for k in range(10)}
You probably shouldn't do this but you could also create a subclass of dict which works somewhat like a defaultdict if you override __missing__:
>>> class KeyDict(dict):
... def __missing__(self, key):
... #self[key] = key # Maybe add this also?
... return key
...
>>> d = KeyDict()
>>> d[1]
1
>>> d[2]
2
>>> d[3]
3
>>> print(d)
{}
>>> {i:i for i in range(1, 11)}
{1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10}
I really like the #mgilson comment, since if you have a two iterables, one that corresponds to the keys and the other the values, you can also do the following.
keys = ['a', 'b', 'c']
values = [1, 2, 3]
d = dict(zip(keys, values))
giving
d = {'a': 1, 'b': 2, 'c': 3}
Consider this example of counting the occurrence of words in a list using dictionary comprehension
my_list = ['hello', 'hi', 'hello', 'today', 'morning', 'again', 'hello']
my_dict = {k:my_list.count(k) for k in my_list}
print(my_dict)
And the result is
{'again': 1, 'hi': 1, 'hello': 3, 'today': 1, 'morning': 1}
Use dict() on a list of tuples, this solution will allow you to have arbitrary values in each list, so long as they are the same length
i_s = range(1, 11)
x_s = range(1, 11)
# x_s = range(11, 1, -1) # Also works
d = dict([(i_s[index], x_s[index], ) for index in range(len(i_s))])
The main purpose of a list comprehension is to create a new list based on another one without changing or destroying the original list.
Instead of writing
l = []
for n in range(1, 11):
l.append(n)
or
l = [n for n in range(1, 11)]
you should write only
l = range(1, 11)
In the two top code blocks you're creating a new list, iterating through it and just returning each element. It's just an expensive way of creating a list copy.
To get a new dictionary with all keys set to the same value based on another dict, do this:
old_dict = {'a': 1, 'c': 3, 'b': 2}
new_dict = { key:'your value here' for key in old_dict.keys()}
You're receiving a SyntaxError because when you write
d = {}
d[i for i in range(1, 11)] = True
you're basically saying: "Set my key 'i for i in range(1, 11)' to True" and "i for i in range(1, 11)" is not a valid key, it's just a syntax error. If dicts supported lists as keys, you would do something like
d[[i for i in range(1, 11)]] = True
and not
d[i for i in range(1, 11)] = True
but lists are not hashable, so you can't use them as dict keys.
A dictionary comprehension is very much like a list comprehension, but we get a dictionary at the end of it, so we need to be assigning key value pairs instead of only values.
Let's say we've got a list of users, where each user information is stored in a tuple. So we have a list with four user tuples. Inside it, they have an ID, a unique identifying number for each user, a username, and a password.
So, we want to create a mapping of usernames to user information.
This is something that you'll be doing very often, especially if you're doing something like web applications and things like that.
users = [
(0, "Bob", "password"),
(1, "code", "python"),
(2, "Stack", "overflow"),
(3, "username", "1234"),
]
username_mapping = {user[1]: user for user in users}
userid_mapping = {user[0]: user for user in users}
print(username_mapping)
"""
Why can this be helpful?
Well, imagine you know a user's username,and you want to get their information out.
You just access, let's say, "Bob," in your username_mapping, and you've got the information out.
"""
print(username_mapping["Bob"]) # (0, "Bob", "password")
# -- Can be useful to log in for example --
username_input = input("Enter your username: ")
password_input = input("Enter your password: ")
_, username, password = username_mapping[username_input]
if password_input == password:
print("Your details are correct!")
else:
print("Your details are incorrect.")
So this is an example of performing some sort of log-in using this structure here, this dictionary comprehension.
This is really helpful because it saves you from having to do another for loop here, to make sure that you are using the right username for their input.
you can't hash a list like that.
try this instead, it uses tuples
d[tuple([i for i in range(1,11)])] = True

Create a Dictionary of Dictionary from a Tuple of Dictionary Inside a List

I have a tuple like this,
sample_tuple = ([{1:["hello"], 2: ["this"], 3:["is fun"]},{1:["hi"], 2:["how are you"]}],
[{1: ["this"], 2:[], 3:["that"]}, {1:[], 2:["yes"]}])
From this tuple, I would like to create a dictionary that has its key values as dictionary.
Step 1:
Iterate the main big tuple and keep track of the indexes of lists.
Step 2:
Get into the lists inside the tuple and keep track of the index of those big lists.
i.e, index 0 of first list,
[{1:["hello"], 2: ["this"], 3:["is fun"]},{1:["hi"], 2:["how are you"]}]
Step 3:
I want to iterate through the key and values of dictionary inside the list.
i.e first dictionary
{1:["hello"], 2: ["this"], 3:["is fun"]}
Step 4:
While iterating through the dictionary values I want to check and make sure values are not empty and not None.
When this process happens, I want to create a dictionary. For this dictionary,
KEY: indexes of step 2 (each index of each dictionary in the big list).
VALUES: a dictionary that has key from the step 3's keys (from my dictionary above) and values as (tricky part) a list, if the step 3 dictionary's value is not empty. As you can see below, I have an empty list temporary_keyword_list that should save the non empty lists values into a temporary list, but I am not getting what I want.
Below is what I tried, what I get and what my desired output.
output_1 = {}
for index, each_keyword in enumerate(sample_tuple):
for ind, each_file in enumerate(each_keyword):
temporary_dict = {}
for key, value in each_file.items():
temporary_keyword_list = []
# Check if a value is not empty or not None
if value!= [] and value is not None:
temporary_keyword_list.append(index) ## Here I want to save the index (tricky part)
# Start inserting values into the dictionary.
temporary_dict[key] = temporary_keyword_list
# Final big dictionary
output_1[ind] = temporary_dict
My current output_1 dictionary:
{0: {1: [1], 2: [], 3: [1]}, 1: {1: [], 2: [1]}}
Desired output:
{0: {1: [0, 1], 2: [0], 3: [0, 1]}, 1: {1: [0], 2: [0, 1]}}
Since its tuples, lists and dictionaries I tried my best to explain the problem I have. Please let me know in the comment if this doesn't make sense, I'll try my best to explain. Any help or suggestion would be awesome.
You probably do not need to create temporary lists or dictionaries here as you can obtain all the indices you need from your for loops. The key here is that your initial tuple contains lists which have a similar structure, so in your code, the structure of your final dictionary is already determined after the first iteration of the first for loop. Consider using defaultdict as well when you create the inner dictionaries as you plan to store lists inside them. Then it is all about correctly handling indices and values. The code below should work.
from collections import defaultdict
sample_tuple = ([{1: ["hello"], 2: ["this"], 3: ["is fun"]},
{1: ["hi"], 2: ["how are you"]}],
[{1: ["this"], 2: [], 3: ["that"]}, {1: [], 2: ["yes"]}])
output_1 = {}
for index, each_keyword in enumerate(sample_tuple):
for ind, each_file in enumerate(each_keyword):
if index == 0:
output_1[ind] = defaultdict(list)
for key, value in each_file.items():
if value != [] and value is not None:
output_1[ind][key].append(index)
print(output_1)
To answer your comment, you can manage without defaultdict, but do you really want to do that ?
sample_tuple = ([{1: ["hello"], 2: ["this"], 3: ["is fun"]},
{1: ["hi"], 2: ["how are you"]}],
[{1: ["this"], 2: [], 3: ["that"]}, {1: [], 2: ["yes"]}])
output_1 = {}
for index, each_keyword in enumerate(sample_tuple):
for ind, each_file in enumerate(each_keyword):
for key, value in each_file.items():
if index == 0:
if key == 1:
if value != [] and value is not None:
output_1[ind] = {key: [index]}
else:
if value != [] and value is not None:
output_1[ind][key] = [index]
else:
if value != [] and value is not None:
output_1[ind][key].append(index)
print(output_1)

Fast/Pythonic way to count intervals between repeated list values

I want to make a histogram of all the intervals between repeated values in a list. I wrote some code that works, but it's using a for loop with if statements. I often find that if one can manage to write a version using clever slicing and/or predefined python (numpy) methods, that one can get much faster Python code than using for loops, but in this case I can't think of any way of doing that. Can anyone suggest a faster or more pythonic way of doing this?
# make a 'histogram'/count of all the intervals between repeated values
def hist_intervals(a):
values = sorted(set(a)) # get list of which values are in a
# setup the dict to hold the histogram
hist, last_index = {}, {}
for i in values:
hist[i] = {}
last_index[i] = -1 # some default value
# now go through the array and find intervals
for i in range(len(a)):
val = a[i]
if last_index[val] != -1: # do nothing if it's the first time
interval = i - last_index[val]
if interval in hist[val]:
hist[val][interval] += 1
else:
hist[val][interval] = 1
last_index[val] = i
return hist
# example list/array
a = [1,2,3,1,5,3,2,4,2,1,5,3,3,4]
histdict = hist_intervals(a)
print("histdict = ",histdict)
# correct answer for this example
answer = { 1: {3:1, 6:1},
2: {2:1, 5:1},
3: {1:1, 3:1, 6:1},
4: {6:1},
5: {6:1}
}
print("answer = ",answer)
Sample output:
histdict = {1: {3: 1, 6: 1}, 2: {5: 1, 2: 1}, 3: {3: 1, 6: 1, 1: 1}, 4: {6: 1}, 5: {6: 1}}
answer = {1: {3: 1, 6: 1}, 2: {2: 1, 5: 1}, 3: {1: 1, 3: 1, 6: 1}, 4: {6: 1}, 5: {6: 1}}
^ note: I don't care about the ordering in the dict, so this solution is acceptable, but I want to be able to run on really large arrays/lists and I'm suspecting my current method will be slow.
You can eliminate the setup loop by a carefully constructed defaultdict. Then you're just left with a single scan over the input list, which is as good as it gets. Here I change the resultant defaultdict back to a regular Dict[int, Dict[int, int]], but that's just so it prints nicely.
from collections import defaultdict
def count_intervals(iterable):
# setup
last_seen = {}
hist = defaultdict(lambda: defaultdict(int))
# The actual work
for i, x in enumerate(iterable):
if x in last_seen:
hist[x][i-last_seen[x]] += 1
last_seen[x] = i
return hist
a = [1,2,3,1,5,3,2,4,2,1,5,3,3,4]
hist = count_intervals(a)
for k, v in hist.items():
print(k, dict(v))
# 1 {3: 1, 6: 1}
# 3 {3: 1, 6: 1, 1: 1}
# 2 {5: 1, 2: 1}
# 5 {6: 1}
# 4 {6: 1}
There is an obvious change to make in terms of data structures. instead of using a dictionary of dictionaries for hist use a defaultdict of Counter this lets the code become
from collections import defaultdict, Counter
# make a 'histogram'/count of all the intervals between repeated values
def hist_intervals(a):
values = sorted(set(a)) # get list of which values are in a
# setup the dict to hold the histogram
hist, last_index = defaultdict(Counter), {}
# now go through the array and find intervals
for i, val in enumerate(a):
if val in last_index
interval = i - last_index[val]
hist[val].update((interval,))
last_index[val] = i
return hist
this will be faster as the if's are written in C, and will also be cleaner.

Creating a dict of blank lists that are not the same list [duplicate]

This question already exists:
dict.fromkeys all point to same list [duplicate]
Closed 9 years ago.
I am trying to create a dict of lists that can be appended to in a for loop. However, if I create a dict using fromkeys, the list becomes a copy of a "pointer", not a new list. For example,
newdict = dict.fromkeys(range(10), [])
-- or --
newdict = dict.fromkeys(range(10), list())
both yield the same data structure, a dict with the SAME list as the value pair. So that when any key is updated e.g. - newdict[0].append(100), the corresponding output of print newdict is:
{0: [100], 1: [100], 2: [100], 3: [100], 4: [100], 5: [100], 6: [100], 7: [100], 8: [100], 9: [100]}
Any thoughts on how to avoid this without having to iterate through in a for loop? Thanks in advance.
The two most common approaches are to use a dict comprehension:
>>> d = {k: [] for k in range(10)}
>>> d[3].append(100)
>>> d
{0: [], 1: [], 2: [], 3: [100], 4: [], 5: [], 6: [], 7: [], 8: [], 9: []}
Or to use a defaultdict and forego setting any keys at all:
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> d
defaultdict(<type 'list'>, {})
>>> d[9].append(100)
>>> d
defaultdict(<type 'list'>, {9: [100]})
As a third option, by using setdefault -- e.g. d.setdefault(k, []) instead of d[k], like in the defaultdict case, you can avoid needing to preset []:
>>> d = {}
>>> d.setdefault(3, []).append(100)
>>> d
{3: [100]}
Maybe a dict comprehension?
newdict = {x: [] for x in range(10)}
I think you want to do
newdict[0].append(100)
right?
fromkeys is a static method of the dict class. The default behavior is designed to set a set of dictionary keys to a single value such as set a multi set counter:
>>> d={}.fromkeys('abc',0)
>>> d
{'a': 0, 'c': 0, 'b': 0}
>>> d['a']+=1
>>> d
{'a': 1, 'c': 0, 'b': 0}
You can patch it to call a function for each element:
>>> class FixFromKeys(dict):
... def fromkeys(cls, seq, func):
... return {key:func() for key in seq}
...
>>> d=FixFromKeys().fromkeys([1,2,3],list)
>>> d[1].append(1)
>>> d
{1: [1], 2: [], 3: []}

how to get all the keys in a 2d dict python

I have a dictionary of form:
d = {123:{2:1,3:1}, 124:{3:1}, 125:{2:1},126:{1:1}}
So, lets look into 2nd degree keys..
123--> 2,3
124--> 3
125--> 2
126--> 1
So total number of unique 2nd order keys are:
1,2,3
Now, i want to modify this dict as
d = {123:{1:0,2:1,3:1}, 124:{1:0,2:0,3:1}, 125:{1:0,2:1,3:0},126:{1:1,2:0,3:0}}
So basically all the 2nd order keys absent in a particular 2d dict.. add that key with value 0.
What is the pythonic way to do this?
Thanks
keyset = set()
for k in d:
keyset.update(d[k])
for k in d:
for kk in keyset:
d[k].setdefault(kk, 0)
In [25]: d = {123:{2:1,3:1}, 124:{3:1}, 125:{2:1},126:{1:1}}
In [26]: se=set(y for x in d for y in d[x])
In [27]: for x in d:
foo=se.difference(d[x])
d[x].update(dict(zip(foo,[0]*len(foo))))
....:
....:
In [30]: d
Out[30]:
{123: {1: 0, 2: 1, 3: 1},
124: {1: 0, 2: 0, 3: 1},
125: {1: 0, 2: 1, 3: 0},
126: {1: 1, 2: 0, 3: 0}}
here use set difference to get the missing keys and then update() the dict:
In [39]: for x in d:
foo=se.difference(d[x])
print foo # missing keys per dict
set([1])
set([1, 2])
set([1, 3])
set([2, 3])
I like the solution of Ashwini Chaudhary.
I edited it to incorporate all the suggestions in the comments with other minor changes for it to look how I would prefer it:
Edited (incorporates the suggestion of Steven Rumbalski to this answer).
all_second_keys = set(key for value in d.itervalues() for key in value)
for value in d.itervalues():
value.update((key,0) for key in all_second_keys if key not in value)
import operator
second_order_keys = reduce(operator.__or__,
(set(v.iterkeys()) for v in d.itervalues()))
for v in d.itervalues():
for k in second_order_keys:
v.setdefault(k, 0)
Or, in Python 3:
from functools import reduce
import operator
second_order_keys = reduce(operator.__or__,
(v.keys() for v in d.values()))
for v in d.values():
for k in second_order_keys:
v.setdefault(k, 0)

Categories

Resources