I'm a Python newbie. As a fun exercise, I thought I would create a list of dictionaries from a list of tuples. Little did I know I would bang my head against the wall for hours.
boys = [("Joe", 7, 125), ("Sam", 8, 130), ("Jake", 9, 225)]
keys = ("Name","Height","Weight")
boyz = []
for x in boys:
z = dict(zip(keys,boys[x]))
boyz.append(z)
print(boyz)
When the x in "boys[x]" is replaced with a integer, it works great, but replacing it with a variable within the for loop won't work. WHY?? I'd love an answer to that specifically. But also if there's a more concise to write this whole thing, please let me know.
In each iteration of the for x in boys loop, x will be the value of the next tuple in the list. It is not an integer you can use as an index. Use x instead of boys[x] in the zip to get the result you want.
for x in boys:
z = dict(zip(keys,x))
boyz.append(z)
You are using boys[x] instead of x.
This raises the error:
TypeError: list indices must be integers, not tuple
Here is your edited code:
boys = [("Joe", 7, 125), ("Sam", 8, 130), ("Jake", 9, 225)]
keys = ("Name","Height","Weight")
boyz = []
for x in boys:
z = dict(zip(keys,x))
boyz.append(z)
print(boyz)
This runs as:
>>> boys = [("Joe", 7, 125), ("Sam", 8, 130), ("Jake", 9, 225)]
>>> keys = ("Name","Height","Weight")
>>> boyz = []
>>> for x in boys:
... z = dict(zip(keys,x))
... boyz.append(z)
...
>>> print(boyz)
[{'Name': 'Joe', 'Weight': 125, 'Height': 7}, {'Name': 'Sam', 'Weight': 130, 'Height': 8}, {'Name': 'Jake', 'Weight': 225, 'Height': 9}]
>>>
boys is a list. lists only support indices that are integers but you're passing in a tuple. You'll want to use x as the tuple.
Ultimately, your goal is to get an iterable of keys and values to pass in to zip.
dict(zip(keys, values))
A more concise version, as you asked, can be achieved using list comprehension.
boyz = [dict(zip(keys, boy)) for boy in boys]
Generally, when you see the pattern of creating an empty list, iterating over some iterable and appending its values after map / filtering, you can use a list comprehension instead.
This:
new_list = []
for item in iterable:
if condition(item):
new_value = mapping(item)
new_list.append(new_value)
Is equivalent to:
new_list = [mapping(item) for item in iterable if condition(item)]
Related
i have this code:
list1 = [['player1', 5,1,300,100, ..., n],['player2', 10,5,650,150,...n],['player3', 17,6,1100,1050...,n]]
dictionary = {
'playersname':[]
'totalwin':[]
'totalloss':[]
'moneywon':[]
'moneyloss':[]
}
for x in listplayers:
dictionary['name'].append(x[0])
dictionary['totalwins'].append(x[1])
dictionary['totalloss'].append(x[2])
dictionary['moneywon'].append(x[3])
dictionary['moneylost'].append(x[4])
my output:
dictionary = {
'name': [player1,player2,player3,...,n],
'totalwin':[5,10,17,...,n],
'totalloss':[1,5,6],
'moneywon':[300,650,1100],
'moneyloss':[100,150,1050],
}
it works just fine, but i have to write out every dictionary keys and append every items individually
(ex:dictionary['totalwins'].append(x[1]))
so if i had a dictionary with 30 keys and a list with 30 different players caracteristics(ex:win, lost, etc) i would have to write 30 lines.
Is there a way to write the same code in fewer lines (ex:loop through everything) instead of writing 30 lines like so:
1 for x in listplayers:
2 dictionary['name'].append(x[0])
3 dictionary['totalwins'].append(x[1])
... ...
30 dictionary['key30'].append(x[30])
If you make a list of keys, you can zip up the values, then zip that up with the key passing the whole thing to dict()
listplayers = [['player1',5,1,300,100], ['player2',10,5,650,150], ['player3',17,6,1100,1050]]
keys = ['playersname','totalwins','totalloss','moneywon','moneylost']
dictionary = dict(zip(keys, zip(*listplayers)))
dictionary
# {'playersname': ('player1', 'player2', 'player3'),
# 'totalwins': (5, 10, 17),
# 'totalloss': (1, 5, 6),
# 'moneywon': (300, 650, 1100),
# 'moneylost': (100, 150, 1050)}
Notice, this give you tuples, not lists. If that's a problem, you can wrap the zips in a dict comprehension or use map to convert them:
dictionary = {key: list(values) for key, values in zip(keys, zip(*listplayers))}
or
dictionary = dict(zip(keys, map(list,zip(*listplayers))))
You could do the following.
list1 = [['player1', 5,1,300,100],['player2', 10,5,650,150]]
dictionary = {f'key_{i}':[*x] for i,x in enumerate(zip(*list1))}
The resulting dictionary:
{'key_0': ['player1', 'player2'],
'key_1': [5, 10],
'key_2': [1, 5],
'key_3': [300, 650],
'key_4': [100, 150]}
Or, if you have some key names in mind:
list1 = [['player1', 5,1,300,100],['player2', 10,5,650,150]]
keys = ['playersname',
'totalwin',
'totalloss',
'moneywon',
'moneyloss']
{keys[i]:[*x] for i,x in enumerate(zip(*list1))}
The result:
{'playersname': ['player1', 'player2'],
'totalwin': [5, 10],
'totalloss': [1, 5],
'moneywon': [300, 650],
'moneyloss': [100, 150]}
I am not sure if I can make myself clear but will try.
I have a tuple in python which I go through as follows (see code below). While going through it, I maintain a counter (let's call it 'n') and 'pop' items that meet a certain condition.
Now of course once I pop the first item, the numbering all goes wrong, how can I do what I want to do more elegantly while removing only certain entries of a tuple on the fly?
for x in tupleX:
n=0
if (condition):
tupleX.pop(n)
n=n+1
As DSM mentions, tuple's are immutable, but even for lists, a more elegant solution is to use filter:
tupleX = filter(str.isdigit, tupleX)
or, if condition is not a function, use a comprehension:
tupleX = [x for x in tupleX if x > 5]
if you really need tupleX to be a tuple, use a generator expression and pass that to tuple:
tupleX = tuple(x for x in tupleX if condition)
Yes we can do it.
First convert the tuple into an list, then delete the element in the list after that again convert back into tuple.
Demo:
my_tuple = (10, 20, 30, 40, 50)
# converting the tuple to the list
my_list = list(my_tuple)
print my_list # output: [10, 20, 30, 40, 50]
# Here i wanna delete second element "20"
my_list.pop(1) # output: [10, 30, 40, 50]
# As you aware that pop(1) indicates second position
# Here i wanna remove the element "50"
my_list.remove(50) # output: [10, 30, 40]
# again converting the my_list back to my_tuple
my_tuple = tuple(my_list)
print my_tuple # output: (10, 30, 40)
Thanks
In Python 3 this is no longer an issue, and you really don't want to use list comprehension, coercion, filters, functions or lambdas for something like this.
Just use
popped = unpopped[:-1]
Remember that it's an immutable, so you will have to reassign the value if you want it to change
my_tuple = my_tuple[:-1]
Example
>>> foo= 3,5,2,4,78,2,1
>>> foo
(3, 5, 2, 4, 78, 2, 1)
foo[:-1]
(3, 5, 2, 4, 78, 2)
If you want to have the popped value,,
>>> foo= 3,5,2,4,78,2,1
>>> foo
(3, 5, 2, 4, 78, 2, 1)
>>> foo, bit = foo[:-1], foo[-1]
>>> bit
1
>>> foo
(3, 5, 2, 4, 78, 2)
Or, to work with each value of a tuple starting at the back...
foo = 3,5,2,4,78,2,1
for f in reversed(foo):
print(f) # 1; 2; 78; ...
Or, with the count...
foo = 3,5,2,4,78,2,1
for f, i in enumerate(reversed(foo)):
print(i, f) # 0 1; 1 2; 2 78; ...
Or, to coerce into a list..
bar = [*foo]
#or
bar = list(foo)
ok I figured out a crude way of doing it.
I store the "n" value in the for loop when condition is satisfied in a list (lets call it delList) then do the following:
for ii in sorted(delList, reverse=True):
tupleX.pop(ii)
Any other suggestions are welcome too.
Maybe you want dictionaries?
d = dict( (i,value) for i,value in enumerate(tple))
while d:
bla bla bla
del b[x]
There is a simple but practical solution.
As DSM said, tuples are immutable, but we know Lists are mutable.
So if you change a tuple to a list, it will be mutable. Then you can delete the items by the condition, then after changing the type to a tuple again. That’s it.
Please look at the codes below:
tuplex = list(tuplex)
for x in tuplex:
if (condition):
tuplex.pop(tuplex.index(x))
tuplex = tuple(tuplex)
print(tuplex)
For example, the following procedure will delete all even numbers from a given tuple.
tuplex = (1, 2, 3, 4, 5, 6, 7, 8, 9)
tuplex = list(tuplex)
for x in tuplex:
if (x % 2 == 0):
tuplex.pop(tuplex.index(x))
tuplex = tuple(tuplex)
print(tuplex)
if you test the type of the last tuplex, you will find it is a tuple.
Finally, if you want to define an index counter as you did (i.e., n), you should initialize it before the loop, not in the loop.
A shorter way perhaps:
tup = (0, 1, 2, 3)
new_tup = (*tup[:-2], tup[-1])
print(new_tup) # (0, 1, 3)
The best solution is the tuple applied to a list comprehension, but to extract one
item this could work:
def pop_tuple(tuple, n):
return tuple[:n]+tuple[n+1:], tuple[n]
say you have a dict with tuples as keys, e.g: labels = {(1,2,0): 'label_1'} you can modify the elements of the tuple keys as follows:
formatted_labels = {(elem[0],elem[1]):labels[elem] for elem in labels}
Here, we ignore the last elements.
One solution is to convert to set and bring back to tuple
tupleX = (
"ZAR",
"PAL",
"SEV",
"ALC",
"LPA",
"TFN",)
remove = (
"LPA",
"TFN",)
tuple(set(tupleX) - set(remove))
('ZAR', 'PAL', 'ALC', 'SEV')
I have a dict like below:
{'activity_count': [10, 11, 12], 'type': ['all', 'paper', 'fpy']}
I want to transform this dict into this form:
{'all': {'activity_count': 10}, 'paper': {'activity_count': 11}, 'fpy': {'activity_count': 12}}
How can I solve this?
So far I tried this solution,
dic={"activity_count":[10,11,12],"type":["all","paper","fpy"]}
in={}
i=0
for val in dic['type']:
for v in dic['activity_count']:
if i== dic['activity_count'].index(v):
temp={}
temp['activity_count']=v
fin[val]=temp
i+=1
It works as I expected, but it looks very ineffective way to achieve this task. Is there a way to solve this problem?
Here a try, here zip is used to get values from both lists and to assign each:
d = {'activity_count': [10, 11, 12], 'type': ['all', 'paper', 'fpy']}
nd = {j:{'activity_count':i} for i, j in zip(d['activity_count'], d['type'])}
print(nd)
I would go for zip and dict comprehension:
test = {'activity_count': [10, 11, 12], 'type': ['all', 'paper', 'fpy']}
solution = {key:{'activity_count':value} for value, key in zip(test["activity_count"],test["type"])}
Explanation: The zip of your two list groups the elements of the two list by with identical index. So it will convert your lists to a generator where the values are like this: [(10, 'all'), (11, 'paper'), (12, 'fpy')]. But the generator is lazy evaluated, so the tuples are only processed, when the dict comprehension asks for them, this saves memory.
The dict comprehension just iterates over this generator and puts the second element as key and the first one as value.
You could try this dictionary comprehension using enumerate:
dictionary = {'activity_count': [10, 11, 12], 'type': ['all', 'paper', 'fpy']}
{e:{"activity_count":dictionary.get("activity_count")[c]} for c,e in enumerate(dictionary.get("type"))}
I'm looking for the greatest number out of a list to then obtain the element 1 location before If anyone knows how to do this it would be very much appreciated.
my_list = ['room', 10, 'chamber', 23, 'kitchen', 8]
pos = my_list.aMethodToGetTheGreatestValuePosition()
print('The biggest room is ' + my_list[pos-1])
This will do it without having to traverse the list multiple times:
my_list = ['room', 10, 'chamber', 23, 'kitchen', 8]
pos = max(enumerate(my_list[1::2]), key=lambda x: x[1])[0]
print('The biggest room is ' + my_list[2*pos])
This uses enumerate to get the indexes of my_list at the same time it is searching for the max.
Or you can be slightly clever with zip:
print('The biggest room is ' + max(zip(*[iter(my_list)]*2), key=lambda x: x[1])[0])
which relies upon using the same iterator over my_list to feed successive values to zip (borrowed from another excellent answer). This essentially turns your flat list into a list of tuples which would be a nicer way of storing the original data, if you have that option:
>>> list(zip(*[iter(my_list)]*2))
[('room', 10), ('chamber', 23), ('kitchen', 8)]
Here's one way. Note this requires structure, i.e. room, then size sequentially. I don't think that's a bad idea, since you should be using a dictionary or list of tuples anyway.
my_list = ['room', 10, 'chamber', 23, 'kitchen', 8]
pos = my_list.index(max(my_list[1::2])) # 23
print('The biggest room is ' + my_list[pos-1]) # chamber
my_list = ['room', 10, 'chamber', 23, 'kitchen', 8]
my_list[my_list.index(max(filter(lambda x: isinstance(x, int), my_list)))-1]
Say there are 2 equal maximum numbers in the input list, it will take the first one. That will be a limitation to the solution
How about:
my_list = ['room', 10, 'chamber', 23, 'kitchen', 8]
max_index = max(range(len(mylist)),
key=lambda i: my_list[i] if isinstance(my_list[i], int) else float('-inf'))
max_name = my_list[max_index-1]
I'd recommend changing your data format though, if you can. A dictionary mapping number to name would (or name to number) would be a lot more natural. Even a list of lists might be easier to deal with.
I am not sure if I can make myself clear but will try.
I have a tuple in python which I go through as follows (see code below). While going through it, I maintain a counter (let's call it 'n') and 'pop' items that meet a certain condition.
Now of course once I pop the first item, the numbering all goes wrong, how can I do what I want to do more elegantly while removing only certain entries of a tuple on the fly?
for x in tupleX:
n=0
if (condition):
tupleX.pop(n)
n=n+1
As DSM mentions, tuple's are immutable, but even for lists, a more elegant solution is to use filter:
tupleX = filter(str.isdigit, tupleX)
or, if condition is not a function, use a comprehension:
tupleX = [x for x in tupleX if x > 5]
if you really need tupleX to be a tuple, use a generator expression and pass that to tuple:
tupleX = tuple(x for x in tupleX if condition)
Yes we can do it.
First convert the tuple into an list, then delete the element in the list after that again convert back into tuple.
Demo:
my_tuple = (10, 20, 30, 40, 50)
# converting the tuple to the list
my_list = list(my_tuple)
print my_list # output: [10, 20, 30, 40, 50]
# Here i wanna delete second element "20"
my_list.pop(1) # output: [10, 30, 40, 50]
# As you aware that pop(1) indicates second position
# Here i wanna remove the element "50"
my_list.remove(50) # output: [10, 30, 40]
# again converting the my_list back to my_tuple
my_tuple = tuple(my_list)
print my_tuple # output: (10, 30, 40)
Thanks
In Python 3 this is no longer an issue, and you really don't want to use list comprehension, coercion, filters, functions or lambdas for something like this.
Just use
popped = unpopped[:-1]
Remember that it's an immutable, so you will have to reassign the value if you want it to change
my_tuple = my_tuple[:-1]
Example
>>> foo= 3,5,2,4,78,2,1
>>> foo
(3, 5, 2, 4, 78, 2, 1)
foo[:-1]
(3, 5, 2, 4, 78, 2)
If you want to have the popped value,,
>>> foo= 3,5,2,4,78,2,1
>>> foo
(3, 5, 2, 4, 78, 2, 1)
>>> foo, bit = foo[:-1], foo[-1]
>>> bit
1
>>> foo
(3, 5, 2, 4, 78, 2)
Or, to work with each value of a tuple starting at the back...
foo = 3,5,2,4,78,2,1
for f in reversed(foo):
print(f) # 1; 2; 78; ...
Or, with the count...
foo = 3,5,2,4,78,2,1
for f, i in enumerate(reversed(foo)):
print(i, f) # 0 1; 1 2; 2 78; ...
Or, to coerce into a list..
bar = [*foo]
#or
bar = list(foo)
ok I figured out a crude way of doing it.
I store the "n" value in the for loop when condition is satisfied in a list (lets call it delList) then do the following:
for ii in sorted(delList, reverse=True):
tupleX.pop(ii)
Any other suggestions are welcome too.
Maybe you want dictionaries?
d = dict( (i,value) for i,value in enumerate(tple))
while d:
bla bla bla
del b[x]
There is a simple but practical solution.
As DSM said, tuples are immutable, but we know Lists are mutable.
So if you change a tuple to a list, it will be mutable. Then you can delete the items by the condition, then after changing the type to a tuple again. That’s it.
Please look at the codes below:
tuplex = list(tuplex)
for x in tuplex:
if (condition):
tuplex.pop(tuplex.index(x))
tuplex = tuple(tuplex)
print(tuplex)
For example, the following procedure will delete all even numbers from a given tuple.
tuplex = (1, 2, 3, 4, 5, 6, 7, 8, 9)
tuplex = list(tuplex)
for x in tuplex:
if (x % 2 == 0):
tuplex.pop(tuplex.index(x))
tuplex = tuple(tuplex)
print(tuplex)
if you test the type of the last tuplex, you will find it is a tuple.
Finally, if you want to define an index counter as you did (i.e., n), you should initialize it before the loop, not in the loop.
A shorter way perhaps:
tup = (0, 1, 2, 3)
new_tup = (*tup[:-2], tup[-1])
print(new_tup) # (0, 1, 3)
The best solution is the tuple applied to a list comprehension, but to extract one
item this could work:
def pop_tuple(tuple, n):
return tuple[:n]+tuple[n+1:], tuple[n]
say you have a dict with tuples as keys, e.g: labels = {(1,2,0): 'label_1'} you can modify the elements of the tuple keys as follows:
formatted_labels = {(elem[0],elem[1]):labels[elem] for elem in labels}
Here, we ignore the last elements.
One solution is to convert to set and bring back to tuple
tupleX = (
"ZAR",
"PAL",
"SEV",
"ALC",
"LPA",
"TFN",)
remove = (
"LPA",
"TFN",)
tuple(set(tupleX) - set(remove))
('ZAR', 'PAL', 'ALC', 'SEV')