If I have a nested dictionary and I want to make a value into a list and add to it, should I do this
mydict[my_key][my_value] = [mydict[my_key][my_value]].append(new_value)
or this
mydict[my_key][my_value] = list(mydict[my_key][my_value]).append(new_value)
The structure looks like:
{'foo': {'bar': 'hi'}}
and I want:
{'foo': {'bar': ['hi', 'bye']}}
You should not do either one.
list.append works in-place and always returns None. So, mydict[my_key][my_value] will be assigned to None after Python executes either of those lines.
You need to call list.append on its own line:
mydict[my_key][my_value] = [mydict[my_key][my_value]]
mydict[my_key][my_value].append(new_value)
Also, list() and [] are two different things.
Putting mydict[my_key][my_value] in square brackets makes a one-item list where mydict[my_key][my_value] is the item.
Using list() however tells Python to iterate over mydict[my_key][my_value] and collect its items into a list. Moreover, a TypeError will be raised if mydict[my_key][my_value] is not iterable.
Below is a demonstration of what I said above:
>>> tup = (1, 2, 3)
>>> [tup] # Places tup in a list
[(1, 2, 3)]
>>> list(tup) # Makes tup into a list
[1, 2, 3]
>>>
>>> [1]
[1]
>>> list(1) # Integers are not iterable
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>>
If you want a list for each dict element, use `defaultdict``
from collections import defaultdict
mydict = defaultdict(list)
mydict[some_key].append(new_value)
Related
This question already has answers here:
What's the difference between lists and tuples?
(22 answers)
Closed 21 days ago.
I am trying to understand the difference between tuples and lists
I was trying to use tuples and lists in a piece of my code, and not realising the difference between tuple and list, could someone please tell me difference,
Thanks,
Gops
Both list and tuple are used to store multiple items within a single collection, but there is a key difference tuple is immutable while list is not. Mutability means the ability to modify the object afterward.
# Here we can modify my_list just fine
>>> my_list = ["hello"]
>>> my_list[0] = "world"
>>> print(my_list)
['world']
# But modifying my_tuple leads to an error
>>> my_tuple = ('hello',)
>>> my_tuple[0] = 'world'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> print(my_tuple)
('h', 'e', 'l', 'l', 'o')
You might think to ask why use tuples at all if we can't mutate them. Wouldn't it be better to just have everything be more flexible?
Well, there are things that tuples can do that lists cannot do such as acting as keys for a dictionary. This is a very useful trick for things like points as keys.
>>> my_dict = {("hello", "world"): "foo"}
>>> my_dict[("hello", "world")]
'foo'
If you try to do the same with lists, you get this error. The error message hints at the key difference. Lists cannot be hashed but tuples can be hashed.
>>> my_dict = {["hello", "world"]: "foo"}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
Sometimes I have a list and I want to do some set actions with it. What I do is to write things like:
>>> mylist = [1,2,3]
>>> myset = set(mylist)
{1, 2, 3}
Today I discovered that from Python 2.7 you can also define a set by directly saying {1,2,3}, and it appears to be an equivalent way to define it.
Then, I wondered if I can use this syntax to create a set from a given list.
{list} fails because it tries to create a set with just one element, the list. And lists are unhashable.
>>> mylist = [1,2,3]
>>> {mylist}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
So, I wonder: is there any way to create a set out of a list using the {} syntax instead of set()?
Basically they are not equivalent (expression vs function). The main purpose of adding {} to python was because of set comprehension (like list comprehension) which you can also create a set using it by passing some hashable objects.
So if you want to create a set using {} from an iterable you can use a set comprehension like following:
{item for item in iterable}
Also note that empty braces represent a dictionary in python not a set. So if you want to just create an empty set the proper way is using set() function.
I asked a related question recently: Python Set: why is my_set = {*my_list} invalid?. My question contains your answer if you are using Python 3.5
>>> my_list = [1,2,3,4,5]
>>> my_set = {*my_list}
>>> my_set
{1, 2, 3, 4, 5}
It won't work on Python 2 (that was my question)
You can use
>>> ls = [1,2,3]
>>> {i for i in ls}
{1,2,3}
I want to generate a list which looks like:
['ret-120','ret-115','ret-110',....'ret-5','ret5',....'ret240']
Please note, there's no ret0 element in the list. So I have to remove it from a list populated by range function. I've tried:
['ret'+str(x) for x in list(range(-120,241,5)).remove(0)]
However this gives out an error:
TypeError: 'NoneType' object is not iterable
Is this possible to accomplish with one line of code?
The simplest way to do what you want is to add a conditional inside your list comprehension:
lst = ['cumRet'+str(x) for x in xrange(-120,241,5) if x != 0]
# This part: ^^^^^^^^^
I also removed the unnecessary list creation and changed range->xrange (note that this range->xrange change is Python2 only)
Your NoneType error is because list.remove(index) modifies in-place, so it returns None.
Hence, you are trying to loop [for x in None].
2-line alternate way (with ;)
tmp = list(range(-120,241,5));tmp.remove(0)
['ret'+str(x) for x in list(range(-120,241,5)).remove(0)]
remove() return None
The list remove() method return None, So 'NoneType' object is not iterable.
Demo:
>>> b = list(range(-120,241,5)).remove(0)
>>> b
>>> print b
None
We will create variable of list and then remove 0 from it.
Demo:
>>> tmp = list(range(-120,241,5))
>>> tmp.remove(0)
>>> ['cumRet'+str(x) for x in tmp]
['cumRet-120', 'cumRet-115', 'cumRet-110', 'cumRet-105', 'cumRet-100', 'cumRet-95', 'cumRet-90', 'cumRet-85', 'cumRet-80', 'cumRet-75', 'cumRet-70', 'cumRet-65', 'cumRet-60', 'cumRet-55', 'cumRet-50', 'cumRet-45', 'cumRet-40', 'cumRet-35', 'cumRet-30', 'cumRet-25', 'cumRet-20', 'cumRet-15', 'cumRet-10', 'cumRet-5', 'cumRet5', 'cumRet10', 'cumRet15', 'cumRet20', 'cumRet25', 'cumRet30', 'cumRet35', 'cumRet40', 'cumRet45', 'cumRet50', 'cumRet55', 'cumRet60', 'cumRet65', 'cumRet70', 'cumRet75', 'cumRet80', 'cumRet85', 'cumRet90', 'cumRet95', 'cumRet100', 'cumRet105', 'cumRet110', 'cumRet115', 'cumRet120', 'cumRet125', 'cumRet130', 'cumRet135', 'cumRet140', 'cumRet145', 'cumRet150', 'cumRet155', 'cumRet160', 'cumRet165', 'cumRet170', 'cumRet175', 'cumRet180', 'cumRet185', 'cumRet190', 'cumRet195', 'cumRet200', 'cumRet205', 'cumRet210', 'cumRet215', 'cumRet220', 'cumRet225', 'cumRet230', 'cumRet235', 'cumRet240']
>>>
Exception Handling:
Best practice to do Exception Handling when we went to remove element from the list because if element not present in the list then it will raise ValueError exception.
Demo:
>>> l = [4,6,8]
>>> l.remove(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list
>>>
>>> try:
... l.remove(3)
... except ValueError:
... print "List not contains remove element."
...
List not contains remove element.
>>>
The problem is that the list.remove() method changes the list in-place and effectively returns None, but you can skip x when it's zero like this:
['ret'+str(x) for x in range(-120, 241, 5) if x]
If you're using Python 2, range() could be changed to xrange() which would avoid creating a temporary list of all the integer values.
Hello my fellow programmers.
I am a fairly new programmer, and now I am facing a great predicament. I am getting the error:
can only assign an iterable
Firstly I don't know what that means.
Secondly I will leave my code for you professionals to critique it:
def num_top(int_lis):
duplic_int_lis = int_lis
int_firs= duplic_int_lis [0]
int_lis[:] = duplic_int_lis [int_firs]
Basically I am trying to find the [0] element in the list and then using that int as an index position to find the integer at that index position.
int_lis[:] = duplic_int_lis [int_firs] means assign all the items of duplic_int_lis [int_firs] to int_lis, so it expects you to pass an iterable/iterator on the RHS.
But in your case you're passing it an non-iterable, which is incorrect:
>>> lis = range(10)
>>> lis[:] = range(5)
>>> lis #all items of `lis` replaced with range(5)
[0, 1, 2, 3, 4]
>>> lis[:] = 5 #Non-iterable will raise an error.
Traceback (most recent call last):
File "<ipython-input-77-0704f8a4410d>", line 1, in <module>
lis[:] = 5
TypeError: can only assign an iterable
>>> lis[:] = 'foobar' #works for any iterable/iterator
>>> lis
['f', 'o', 'o', 'b', 'a', 'r']
As you cannot iterate over an integer, hence the error.
>>> for x in 1: pass
Traceback (most recent call last):
File "<ipython-input-84-416802313c58>", line 1, in <module>
for x in 1:pass
TypeError: 'int' object is not iterable
The RHS of a slice-assignment must be an iterable, not a scalar. Consider slice-deleting and then appending instead.
An iterable is a thing with multiple items that you can iterate through (for example: take the 1st value do something, then the 2nd do something, etc...) Lists, dictionaries, tuples, strings have several items in them and can be used as iterables. As a counterexample: number types don't qualify as iterable.
Remember that computers count from #0 so: if you want the first value of a list you can use
my_list[0]
before you go further I would suggest watching this video about looping. https://www.youtube.com/watch?v=EnSu9hHGq5o
Folks,
Relative n00b to python, trying to find out the diff of two lists of dictionaries.
If these were just regular lists, I could create sets and then do a '-'/intersect operation.
However, set operation does not work on lists of dictionaries:
>>> l = []
>>> pool1 = {}
>>> l.append(pool1)
>>> s = set(l)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
You need a "hashable" dictionary.
The items() attribute is a list of tuples. Make this a tuple() and you have a hashable version of a dictionary.
tuple( sorted( some_dict.items() ) )
You can define your own dict wrapper that defines __hash__ method:
class HashableDict(dict):
def __hash__(self):
return hash(tuple(sorted(self.items())))
this wrapper is safe as long as you do not modify the dictionary while finding the intersection.
Python won't allow you to use a dictionary as a key in either a set or dictionary because it has no default __hash__ method defined. Unfortunately, collections.OrderedDict is also not hashable. There also isn't a built-in dictionary analogue to frozenset. You can either create a subclass of dict with your own hash method, or do something like this:
>>> def dict_item_set(dict_list):
... return set(tuple(*sorted(d.items())) for d in dict_list)
>>> a = [{1:2}, {3:4}]
>>> b = [{3:4}, {5:6}]
>>> dict(dict_item_set(a) - dict_item_set(b))
{1: 2}
>>> dict(dict_item_set(a) & dict_item_set(b))
{3: 4}
Of course, this is neither efficient nor pretty.