What happens when you set a dictionary in python? - python

I was trying out some ideas to solve an unrelated problem when I came across this behavior when using set on a dictionary:
a = {"a": 1}
b = {"b": 2}
c = {"a": 1}
set([a, b, c])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-21-7c1da7b47bae> in <module>
----> 1 set([a, b, c])
TypeError: unhashable type: 'dict'
d = {"a": 1, "b": 2}
set(d)
Out[23]: {'a', 'b'}
set(a)
Out[24]: {'a'}
I kind of understand why the set of dictionaries is unhashable (they're mutable), but the whole thing does not make that much sense to me. Why is set(a) and set(d) returning just the keys and how would that be useful?
Thank you!

set converts an arbitrary iterable to a set, which means getting an iterator for its argument. The iterator for a dict returns its keys. It's not so much about set being useful with a dict, but set not caring what its argument is.
As for why a dict iterator returns the keys of the dict, it's a somewhat arbitrary choice made by the language designer, but keep in mind that given the choice of iterating over the keys, the values, or the key-value pairs, iterating over the keys is probably the best compromise between usefulness and simplicity. (All three are available explicitly via d.keys(), d.values(), and d.items(); in some sense iter(d) is a convenience for the common use case of d.keys().)

The function set(x) takes any iterable x and puts all the iterated values into a set.
Dictionaries are iterable. When you iterate through a dictionary, you are given the keys. So set(d) will give you a new set containing all the keys of the dict d.

Related

creating list out of dictionary keys in python [duplicate]

With Python 2.7, I can get dictionary keys, values, or items as a list:
>>> newdict = {1:0, 2:0, 3:0}
>>> newdict.keys()
[1, 2, 3]
With Python >= 3.3, I get:
>>> newdict.keys()
dict_keys([1, 2, 3])
How do I get a plain list of keys with Python 3?
This will convert the dict_keys object to a list:
list(newdict.keys())
On the other hand, you should ask yourself whether or not it matters. It is Pythonic to assume duck typing -- if it looks like a duck and it quacks like a duck, it is a duck. The dict_keys object can be iterated over just like a list. For instance:
for key in newdict.keys():
print(key)
Note that dict_keys doesn't support insertion newdict[k] = v, though you may not need it.
Python >= 3.5 alternative: unpack into a list literal [*newdict]
New unpacking generalizations (PEP 448) were introduced with Python 3.5 allowing you to now easily do:
>>> newdict = {1:0, 2:0, 3:0}
>>> [*newdict]
[1, 2, 3]
Unpacking with * works with any object that is iterable and, since dictionaries return their keys when iterated through, you can easily create a list by using it within a list literal.
Adding .keys() i.e [*newdict.keys()] might help in making your intent a bit more explicit though it will cost you a function look-up and invocation. (which, in all honesty, isn't something you should really be worried about).
The *iterable syntax is similar to doing list(iterable) and its behaviour was initially documented in the Calls section of the Python Reference manual. With PEP 448 the restriction on where *iterable could appear was loosened allowing it to also be placed in list, set and tuple literals, the reference manual on Expression lists was also updated to state this.
Though equivalent to list(newdict) with the difference that it's faster (at least for small dictionaries) because no function call is actually performed:
%timeit [*newdict]
1000000 loops, best of 3: 249 ns per loop
%timeit list(newdict)
1000000 loops, best of 3: 508 ns per loop
%timeit [k for k in newdict]
1000000 loops, best of 3: 574 ns per loop
with larger dictionaries the speed is pretty much the same (the overhead of iterating through a large collection trumps the small cost of a function call).
In a similar fashion, you can create tuples and sets of dictionary keys:
>>> *newdict,
(1, 2, 3)
>>> {*newdict}
{1, 2, 3}
beware of the trailing comma in the tuple case!
list(newdict) works in both Python 2 and Python 3, providing a simple list of the keys in newdict. keys() isn't necessary.
You can also use a list comprehension:
>>> newdict = {1:0, 2:0, 3:0}
>>> [k for k in newdict.keys()]
[1, 2, 3]
Or, shorter,
>>> [k for k in newdict]
[1, 2, 3]
Note: Order is not guaranteed on versions under 3.7 (ordering is still only an implementation detail with CPython 3.6).
A bit off on the "duck typing" definition -- dict.keys() returns an iterable object, not a list-like object. It will work anywhere an iterable will work -- not any place a list will. a list is also an iterable, but an iterable is NOT a list (or sequence...)
In real use-cases, the most common thing to do with the keys in a dict is to iterate through them, so this makes sense. And if you do need them as a list you can call list().
Very similarly for zip() -- in the vast majority of cases, it is iterated through -- why create an entire new list of tuples just to iterate through it and then throw it away again?
This is part of a large trend in python to use more iterators (and generators), rather than copies of lists all over the place.
dict.keys() should work with comprehensions, though -- check carefully for typos or something... it works fine for me:
>>> d = dict(zip(['Sounder V Depth, F', 'Vessel Latitude, Degrees-Minutes'], [None, None]))
>>> [key.split(", ") for key in d.keys()]
[['Sounder V Depth', 'F'], ['Vessel Latitude', 'Degrees-Minutes']]
If you need to store the keys separately, here's a solution that requires less typing than every other solution presented thus far, using Extended Iterable Unpacking (Python3.x+):
newdict = {1: 0, 2: 0, 3: 0}
*k, = newdict
k
# [1, 2, 3]
Operation
no. Of characters
k = list(d)
9 characters (excluding whitespace)
k = [*d]
6 characters
*k, = d
5 characters
Converting to a list without using the keys method makes it more readable:
list(newdict)
and, when looping through dictionaries, there's no need for keys():
for key in newdict:
print key
unless you are modifying it within the loop which would require a list of keys created beforehand:
for key in list(newdict):
del newdict[key]
On Python 2 there is a marginal performance gain using keys().
Yes, There is a better and simplest way to do this in python3.X
use inbuild list() function
#Devil
newdict = {1:0, 2:0, 3:0}
key_list = list(newdict)
print(key_list)
#[1, 2, 3]
I can think of 2 ways in which we can extract the keys from the dictionary.
Method 1: -
To get the keys using .keys() method and then convert it to list.
some_dict = {1: 'one', 2: 'two', 3: 'three'}
list_of_keys = list(some_dict.keys())
print(list_of_keys)
-->[1,2,3]
Method 2: -
To create an empty list and then append keys to the list via a loop.
You can get the values with this loop as well (use .keys() for just keys and .items() for both keys and values extraction)
list_of_keys = []
list_of_values = []
for key,val in some_dict.items():
list_of_keys.append(key)
list_of_values.append(val)
print(list_of_keys)
-->[1,2,3]
print(list_of_values)
-->['one','two','three']
Beyond the classic (and probably more correct) way to do this (some_dict.keys()) there is also a more "cool" and surely more interesting way to do this:
some_dict = { "foo": "bar", "cool": "python!" }
print( [*some_dict] == ["foo", "cool"] ) # True
Note: this solution shouldn't be used in a develop environment; I showed it here just because I thought it was quite interesting from the *-operator-over-dictionary side of view. Also, I'm not sure whether this is a documented feature or not, and its behaviour may change in later versions :)
You can you use simple method like below
keys = newdict.keys()
print(keys)
This is the best way to get key List in one line of code
dict_variable = {1:"a",2:"b",3:"c"}
[key_val for key_val in dict_variable.keys()]

Why converting dictionaries to lists only returns keys?

I am wondering why when I use list(dictionary) it only returns keys and not their definitions into a list?
For example, I import a glossary with terms and definitions into a dictionary using CSV reader, then use the built in list() function to convert the dictionary to a list, and it only returns keys in the list.
It's not really an issue as it actually allows my program to work well, was just wondering is that just how it is supposed to behave or?
Many thanks for any help.
Do you mean by:
>>> d = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> d.items()
dict_items([('a', [1, 2, 3]), ('b', [4, 5, 6])])
>>> list(d.items())
[('a', [1, 2, 3]), ('b', [4, 5, 6])]
>>>
Dictionary makes list(d) give it's keys, however list(d.values()) will give the values.
Also, in the documentation:
Performing list(d) on a dictionary returns a list of all the keys used in the dictionary.
That tells you all.
why when I use list(dictionary) it only returns keys? ... just wondering is that just how it is supposed to behave or?
Because that's how it's designed to work.
Performing list(d) on a dictionary returns a list of all the keys used in the dictionary.
Because (speculative):
The main operations on a dictionary are storing a value with some key and extracting the value given the key.
The values are not so consequential. Keys are unique identifiers. Values are mapped to keys. So dicts are indexed by key, iterated by key, etc. If you want a list of key/value tuple, then you have to call for that explicitly e.g., list(d.items()).
Dictioanries are iterable over their key values hence you get only the key values returned when you wrap it with the list() function.
The behaviour would be something like this:
>>> dictionary = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> dictionary.items()
dictionary_items([('item_1', [1, 2]), ('item_2', [3, 4])])
You can make use of dictionary.items() to get all the items(keys and values) from the dictionary
>>> list(dictionary.items())
[('item_1', [1, 2]), ('item_2', [3, 4])]
In short: In essence it works that way, because it was designed that way. It makes however sense if we take into account that x in some_dict performs a membercheck on the dictionary keys.
Frequently Python code iterates over a collection, and does not know the type of the collection it iterates over: it can be a list, tuple, set, dictionary, range object, etc.
The question is, do we see a dictionary as a collection, and if yes, a collection of what? If we want to make it collection, there are basically three logical answers to the second question: we can see it as a collection of the keys, of the values, or key-value pairs. Especially keys and key-value pairs are popular. C# for example sees a dictionary as a collection of KeyValuePair<TK, TV>s. Python provides the .values() and .items() method to iterate over the values and key-value pairs.
Dictionaries are mainly designed to perform a fast lookup for a key and retrieve the corresponding value. Therefore the some_key in some_dict would be a sensical query, or (some_key, some_value) in some_dict, since the latter chould check if the key is in the dictionary, and then check if it matches with some_value. The latter is however less flexible, since often we might not want to be interested in the corresponding value, we simply want to check if the dictionary contains a certain key. We furthermore can not support both use cases concurrently, since if the dictionary would for example contain 2-tuples as keys, then that means it is ambiguous if (1, 2) in some_dict would mean that for key 1 the value is 2; or if (1, 2) is a key in the dictionary.
Since the designers of Python decided to define the membership check on dictionaries on the keys, it makes more sense to make a dictionary an iterable over its keys. Indeed, one usually expects that if x in some_iterable holds, then x in list(some_iterable) should hold as well. If the iterable of a dictionary would return 2-tuples of key-value pairs (like C# does), then if we would make a list of these 2-tuples, it would not be in harmony with the membership check on the dictionary itself. Since if 2 in some_dict holds, 2 in list(some_dict) would fail.

python - dictionary with set of tuples as value is not created correctly

I have read this but it does not seem to work for me -
>>> dict = {}
>>> dict[ "a" ] = set(("1111","test1"))
>>> dict
{'a': set(['1111', 'test1'])}
>>> dict[ "a" ].add( ("2222","test2"))
>>> dict
{'a': set(['1111', 'test1', ('2222', 'test2')])}
I was expecting also the first one to look like a tuple - why is that splitted?
I want when doing :
>>> for key,val_set in dict.items() :
... for val in val_set :
... print val
...
1111
test1
('2222', 'test2')
to have 2 items printed not three.
set() takes the values from an iterable and adds each value separately. You passed in a tuple, which is an iterable with two values.
If you wanted to add the tuple itself, you need to wrap that in an iterable, like a list:
set([("1111","test1")])
In Python 3, you can instead use a set display to create a new set:
{("1111","test1")}
A set display takes elements separated by commas, and ("1111", "test1") is one tuple element here.
In the other post, the set was created with a set display (so {tuple1, tuple2, etc.}) and the answers used either an itertools function or a generator expression to produce the sequence of tuples for the set() function to process; a both produce an iterable type.
You have got your answer but I will advice you to use defaultdict instead. All these type of cases like this set([("1111","test1")]) are properly handled. You don't have to worry about initialize too.
Try This.
from collections import defaultdict
s = defaultdict(set)
s["a"].add(("pw", "sq"));
s["a"].add(("wq", "qq"));
s["a"].add(("aa", "bb"));
for k, v in s.items():
print (k)
for g in v:
print (g)
And please note this, I have assumed all your values opposite your keys are sets.
if this is not the case, go with the first one.

How to return dictionary keys as a list in Python?

With Python 2.7, I can get dictionary keys, values, or items as a list:
newdict = {1:0, 2:0, 3:0}
newdict.keys()
# [1, 2, 3]
With Python >= 3.3, I get:
newdict.keys()
# dict_keys([1, 2, 3])
How do I get a plain list of keys with Python 3?
This will convert the dict_keys object to a list:
list(newdict.keys())
On the other hand, you should ask yourself whether or not it matters. It is Pythonic to assume duck typing -- if it looks like a duck and it quacks like a duck, it is a duck. The dict_keys object can be iterated over just like a list. For instance:
for key in newdict.keys():
print(key)
Note that dict_keys doesn't support insertion newdict[k] = v, though you may not need it.
Python >= 3.5 alternative: unpack into a list literal [*newdict]
New unpacking generalizations (PEP 448) were introduced with Python 3.5 allowing you to now easily do:
>>> newdict = {1:0, 2:0, 3:0}
>>> [*newdict]
[1, 2, 3]
Unpacking with * works with any object that is iterable and, since dictionaries return their keys when iterated through, you can easily create a list by using it within a list literal.
Adding .keys() i.e [*newdict.keys()] might help in making your intent a bit more explicit though it will cost you a function look-up and invocation. (which, in all honesty, isn't something you should really be worried about).
The *iterable syntax is similar to doing list(iterable) and its behaviour was initially documented in the Calls section of the Python Reference manual. With PEP 448 the restriction on where *iterable could appear was loosened allowing it to also be placed in list, set and tuple literals, the reference manual on Expression lists was also updated to state this.
Though equivalent to list(newdict) with the difference that it's faster (at least for small dictionaries) because no function call is actually performed:
%timeit [*newdict]
1000000 loops, best of 3: 249 ns per loop
%timeit list(newdict)
1000000 loops, best of 3: 508 ns per loop
%timeit [k for k in newdict]
1000000 loops, best of 3: 574 ns per loop
with larger dictionaries the speed is pretty much the same (the overhead of iterating through a large collection trumps the small cost of a function call).
In a similar fashion, you can create tuples and sets of dictionary keys:
>>> *newdict,
(1, 2, 3)
>>> {*newdict}
{1, 2, 3}
beware of the trailing comma in the tuple case!
list(newdict) works in both Python 2 and Python 3, providing a simple list of the keys in newdict. keys() isn't necessary.
You can also use a list comprehension:
>>> newdict = {1:0, 2:0, 3:0}
>>> [k for k in newdict.keys()]
[1, 2, 3]
Or, shorter,
>>> [k for k in newdict]
[1, 2, 3]
Note: Order is not guaranteed on versions under 3.7 (ordering is still only an implementation detail with CPython 3.6).
A bit off on the "duck typing" definition -- dict.keys() returns an iterable object, not a list-like object. It will work anywhere an iterable will work -- not any place a list will. a list is also an iterable, but an iterable is NOT a list (or sequence...)
In real use-cases, the most common thing to do with the keys in a dict is to iterate through them, so this makes sense. And if you do need them as a list you can call list().
Very similarly for zip() -- in the vast majority of cases, it is iterated through -- why create an entire new list of tuples just to iterate through it and then throw it away again?
This is part of a large trend in python to use more iterators (and generators), rather than copies of lists all over the place.
dict.keys() should work with comprehensions, though -- check carefully for typos or something... it works fine for me:
>>> d = dict(zip(['Sounder V Depth, F', 'Vessel Latitude, Degrees-Minutes'], [None, None]))
>>> [key.split(", ") for key in d.keys()]
[['Sounder V Depth', 'F'], ['Vessel Latitude', 'Degrees-Minutes']]
If you need to store the keys separately, here's a solution that requires less typing than every other solution presented thus far, using Extended Iterable Unpacking (Python3.x+):
newdict = {1: 0, 2: 0, 3: 0}
*k, = newdict
k
# [1, 2, 3]
Operation
no. Of characters
k = list(d)
9 characters (excluding whitespace)
k = [*d]
6 characters
*k, = d
5 characters
Converting to a list without using the keys method makes it more readable:
list(newdict)
and, when looping through dictionaries, there's no need for keys():
for key in newdict:
print key
unless you are modifying it within the loop which would require a list of keys created beforehand:
for key in list(newdict):
del newdict[key]
On Python 2 there is a marginal performance gain using keys().
Yes, There is a better and simplest way to do this in python3.X
use inbuild list() function
#Devil
newdict = {1:0, 2:0, 3:0}
key_list = list(newdict)
print(key_list)
#[1, 2, 3]
I can think of 2 ways in which we can extract the keys from the dictionary.
Method 1: -
To get the keys using .keys() method and then convert it to list.
some_dict = {1: 'one', 2: 'two', 3: 'three'}
list_of_keys = list(some_dict.keys())
print(list_of_keys)
-->[1,2,3]
Method 2: -
To create an empty list and then append keys to the list via a loop.
You can get the values with this loop as well (use .keys() for just keys and .items() for both keys and values extraction)
list_of_keys = []
list_of_values = []
for key,val in some_dict.items():
list_of_keys.append(key)
list_of_values.append(val)
print(list_of_keys)
-->[1,2,3]
print(list_of_values)
-->['one','two','three']
Beyond the classic (and probably more correct) way to do this (some_dict.keys()) there is also a more "cool" and surely more interesting way to do this:
some_dict = { "foo": "bar", "cool": "python!" }
print( [*some_dict] == ["foo", "cool"] ) # True
Note: this solution shouldn't be used in a develop environment; I showed it here just because I thought it was quite interesting from the *-operator-over-dictionary side of view. Also, I'm not sure whether this is a documented feature or not, and its behaviour may change in later versions :)
You can you use simple method like below
keys = newdict.keys()
print(keys)
This is the best way to get key List in one line of code
dict_variable = {1:"a",2:"b",3:"c"}
[key_val for key_val in dict_variable.keys()]
Get a list of keys with specific values
You can select a subset of the keys that satisfies a specific condition. For example, if you want to select the list of keys where the corresponding values are not None, then use
[k for k,v in newdict.items() if v is not None]
Slice the list of keys in a dictionary
Since Python 3.7, dicts preserve insertion order. So one use case of list(newdict) might be to select keys from a dictionary by its index or slice it (not how it's "supposed" to be used but certainly a possible question). Instead of converting to a list, use islice from the built-in itertools module, which is much more efficient since converting the keys into a list just to throw away most of it is very wasteful. For example, to select the second key in newdict:
from itertools import islice
next(islice(newdict, 1, 2))
or to slice the second to fifth key:
list(islice(newdict, 1, 6))
For large dicts, it's thousands of times faster than list(newdict)[1] etc.

Python dictionary with list keyword

I'm coding a N'th order markov chain.
It goes something like this:
class Chain:
def __init__(self, order):
self.order = order
self.state_table = {}
def train(self, next_state, *prev_states):
if len(prev_states) != self.order: raise ValueError("prev_states does not match chain order")
if prev_states in self.state_table:
if next_state in self.state_table[prev_states]:
self.state_table[prev_states][next_state] += 1
else:
self.state_table[prev_states][next_state] = 0
else:
self.state_table[prev_states] = {next_state: 0}
Unfortunally, list and tuples are unhashable, and I cannot use them as keywords in dicts...
I have hopefully explained my problem well enough for you to understand what I try to achieve.
Any good ideas how I can use multiple values for dictionary keyword?
Followup question:
I did not know that tuples are hashable.
But the entropy for the hashes seem low. Are there hash collisions possible for tuples?!
Tuples are hashable when their contents are.
>>> a = {}
>>> a[(1,2)] = 'foo'
>>> a[(1,[])]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
As for collisions, when I try a bunch of very similar tuples, I see them being mapped widely apart:
>>> hash((1,2))
3713081631934410656
>>> hash((1,3))
3713081631933328131
>>> hash((2,2))
3713082714462658231
>>> abs(hash((1,2)) - hash((1,3)))
1082525
>>> abs(hash((1,2)) - hash((2,2)))
1082528247575
You can use tuples as dictionary keys, they are hashable as long as their content is hashable (as #larsman said).
Don't worry about collisions, Python's dict takes care of it.
>>> hash('a')
12416037344
>>> hash(12416037344)
12416037344
>>> hash('a') == hash(12416037344)
True
>>> {'a': 'one', 12416037344: 'two'}
{'a': 'one', 12416037344: 'two'}
In this example I took a string and an integer. But it works the same with tuples. Just didn't have any idea how to find two tuples with identical hashes.

Categories

Resources