I have two list in same size in python and want to merge them to become one list with the same number size as before
first one :
['add ', 'subtract ', 'multiply ', 'divide ']
second one :
[3, 2, 3, 2]
and i want output came like :
['add 3', 'subtract 2', 'multiply 3', 'divide 2']
How can I do that?
I tried this:
list3 = functions_name + main_function_count
but the output is :
['add ', 'subtract ', 'multiply ', 'divide ', 3, 2, 3, 2]
Use a combination of list comprehension with zip and f-strings
list1 = ['add ', 'subtract ', 'multiply ', 'divide ']
list2 = [3, 2, 3, 2]
result = [f'{x} {y}' for x, y in zip(list1, list2)]
+ is adding the lists themselves, you want to apply + to each element.
ops = ['add ', 'subtract ', 'multiply ', 'divide ']
nums = [3, 2, 3, 2]
list3 = [op+str(n) for op, n in zip(ops, nums)]
# or using an fstring to remove "+" entirely
list3 = [f"{op}{n}" for op, n in zip(ops, nums)]
zip lets you iterate multiple "iterables", like lists, in parallel.
edit: changed n to str(n), fstring
Using list comprehension:
a = ['add ', 'subtract ', 'multiply ', 'divide ']
b = [3, 2, 3, 2]
# Here:
# zip(a, b) iterates through a and b in parallel
# for x,y assigns corressponding values from a and b
# f'{x} {y}' combines the values with a separating space.
# [...] is a "list comprehension"
c = [ f'{x} {y}' for x,y in zip(a, b) ]
print(c)
Outputs:
['add 3', 'subtract 2', 'multiply 3', 'divide 2']
You could do it like this:
list1 = ['add ', 'subtract ', 'multiply ', 'divide ']
list2 = [3, 2, 3, 2]
list3 = []
for y,x in enumerate(list1):
list3.append("%s%d" % (x,list2[y]))
You can try it:
list1 = ['add ', 'subtract ', 'multiply ', 'divide ']
list2 = [3, 2, 3, 2]
result = []
for i,j in zip(list1,list2):
result.append(str(i)+str(j))
print(result)
Output:
['add 3', 'subtract 2', 'multiply 3', 'divide 2']
This is a good case for a "List comprehension"!
You can essentially make a small for loop in a python 1-liner as below. Note that to concatenate the values you have to declare the int as a str. You could also do this with f-strings, but I think this is a clearer explanation:
l1 = [1,2,3,4]
l2 = ['a','b','c','d']
result = [str(la)+lb for la,lb in zip(l1,l2)]
returns
result = ['1a', '2b', '3c', '4d']
Here we're using zip() it index along two lists simultaneously in the list comprehension, and simply concatenating the elements as we go along.
EDIT: To do this without a plus, we can use an f-string as follows:
result = [f"{la} {lb}" for la,lb in zip(l1,l2)]
This returns the same value, but doesn't use a plus operator (and you don't have to declare a type str(), the f-string does that for you.)
You can add each element together, making sure that numbers are converted to strings:
functions_name = ['add ', 'subtract ', 'multiply ', 'divide ']
main_function_count = [3, 2, 3, 2]
list3 = [name+str(count) for name,count in zip(functions_name, main_function_count)]
print(list3)
Output as requested
Or, without using + to concatenate strings:
list3 = [f'{name}{count}' for name,count in zip(functions_name, main_function_count)]
One more, seems I'll never get tired of pointing out that map can use multiple iterables:
ops = ['add ', 'subtract ', 'multiply ', 'divide ']
nums = [3, 2, 3, 2]
list3 = list(map('{}{}'.format, ops, nums))
Related
I have a header list as below:
h_list = ['h1','h2','h3','h4','h5']
Now I have data list (Nested):
d_list = [
[1, None, 3, ' ', 5],
[1, ' ', 2, ' ', 9]
]
Both lists are of same length every time, so I want to match in each list of nested list at same index position and if its all corresponding values are either None or ' ', then replace the item from h_list to ' ' (Empty string)
My expected output is:
h_list = ['h1',' ','h3',' ','h5']
Try a list comprehension:
h_list = ['h1','h2','h3','h4','h5']
d_list = [
[1, None, 3, ' ', 5],
[1, ' ', 2, ' ', 9]
]
empty = [' ', None]
h_list = [' ' if any(b[i] in empty for b in d_list) else v for i, v in enumerate(h_list)]
print(h_list)
Output:
['h1', ' ', 'h3', ' ', 'h5']
Breaking down this part of the code:
h_list = [' ' if any(b[i] in empty for b in d_list) else v for i, v in enumerate(h_list)]
First, lets have only
[(i, v) for i, v in enumerate(h_list)]
The above will be a list of the indices and values of each element in h_list.
Now, we use an if statement to determine when to add the ' '. First, we need to recognize the any() function:
any(b[i] in empty for b in d_list)
returns True if any of the arrays inside d_list at index i is in the empty list. We want None and ' ' to be in place for all the strings in h_list that its index returns a ' ' or None for any of the lists in d_list, so:
[' ' for i, v in enumerate(h_list) if any(b[i] in empty for b in d_list)]
Finally, we want to use the original string if not any(b[i] in empty for b in d_list). For that, we use an else statement (note that with an else, the statements get shifted to the left side of the for loop.):
h_list = [' ' if any(b[i] in empty for b in d_list) else v for i, v in enumerate(h_list)]
I believe this should work for your examples:
new_list = []
for orig_element, *values in zip(h_list, *d_list):
new_list.append(orig_element if any(not (v is None or str(v).strip() == '') for v in values) else '')
If you want to modify the list in-place simply do:
for i, (orig_element, *values) in enumerate(h_list, *d_list):
h_list[i] = orig_element if any(not (v is None or str(v).strip() == '') for v in values) else ''
You can use zip with all:
h_list = ['h1','h2','h3','h4','h5']
d_list = [[1, None, 3, ' ', 5], [1, ' ', 2, ' ', 9]]
r = [' ' if all(k in {None, ' '} for k in j) else a for a, j in zip(h_list, zip(*d_list))]
Output:
['h1', ' ', 'h3', ' ', 'h5']
Basic solution
h_list = ['h1','h2','h3','h4','h5']
d_list = [
[1, None, 3, ' ', 5],
[1, ' ', 2, ' ', 9]
]
# loop over d_list
for i in d_list:
# loop over inner list
for k in i:
# if type not int, give me space in that index
if type(k)!=int:
h_list[i.index(k)]=" "
h_list
I have a set of numbers that I want to align considering the comma:
10 3
200 4000,222 3 1,5
200,21 0,3 2
30000 4,5 1
mylist = [['10', '3', '', ''],
['200', '4000,222', '3', '1,5'],
['200,21', '', '0,3', '2'],
['30000', '4,5', '1', '']]
What I want is to align this list considering the comma:
expected result:
mylist = [[' 10 ', ' 3 ', ' ', ' '],
[' 200 ', '4000,222', '3 ', '1,5'],
[' 200,21', ' ', '0,3', '2 '],
['30000 ', ' 4,5 ', '1 ', ' ']]
I tried to turn the list:
mynewlist = list(zip(*mylist))
and to find the longest part after the comma in every sublist:
for m in mynewlist:
max([x[::-1].find(',') for x in m]
and to use rjust and ljust but I don't know how to ljust after a comma and rjust before the comma, both in the same string.
How can I resolve this without using format()?
(I want to align with ljust and rjust)
Here's another approach that currently does the trick. Unfortunately, I can't see any simple way to make this work, maybe due to the time :-)
Either way, I'll explain it. r is the result list created before hand.
r = [[] for i in range(4)]
Then we loop through the values and also grab an index with enumerate:
for ind1, vals in enumerate(zip(*mylist)):
Inside the loop we grab the max length of the decimal digits present and the max length of the word (the word w/o the decimal digits):
l = max(len(v.partition(',')[2]) for v in vals) + 1
mw = max(len(v if ',' not in v else v.split(',')[0]) for v in vals)
Now we go through the values inside the tuple vals and build our results (yup, can't currently think of a way to avoid this nesting).
for ind2, v in enumerate(vals):
If it contains a comma, it should be formatted differently. Specifically, we rjust it based on the max length of a word mw and then add the decimal digits and any white-space needed:
if ',' in v:
n, d = v.split(',')
v = "".join((n.rjust(mw),',', d, " " * (l - 1 - len(d))))
In the opposite case, we simply .rjust and then add whitespace:
else:
v = "".join((v.rjust(mw) + " " * l))
finally, we append to r.
r[ind1].append(v)
All together:
r = [[] for i in range(4)]
for ind1, vals in enumerate(zip(*mylist)):
l = max(len(v.partition(',')[2]) for v in vals) + 1
mw = max(len(v if ',' not in v else v.split(',')[0]) for v in vals)
for ind2, v in enumerate(vals):
if ',' in v:
n, d = v.split(',')
v = "".join((n.rjust(mw),',', d, " " * (l - 1 - len(d))))
else:
v = "".join((v.rjust(mw) + " " * l))
r[ind1].append(v)
Now, we can print it out:
>>> print(*map(list,zip(*r)), sep='\n)
[' 10 ', ' 3 ', ' ', ' ']
[' 200 ', '4000,222', '3 ', '1,5']
[' 200,21', ' ', '0,3', '2 ']
['30000 ', ' 4,5 ', '1 ', ' ']
Here's a bit different solution that doesn't transpose my_list but instead iterates over it twice. On the first pass it generates a list of tuples, one for each column. Each tuple is a pair of numbers where first number is length before comma and second number is length of comma & everything following it. For example '4000,222' results to (4, 4). On the second pass it formats the data based on the formatting info generated on first pass.
from functools import reduce
mylist = [['10', '3', '', ''],
['200', '4000,222', '3', '1,5'],
['200,21', '', '0,3', '2'],
['30000', '4,5', '1', '']]
# Return tuple (left part length, right part length) for given string
def part_lengths(s):
left, sep, right = s.partition(',')
return len(left), len(sep) + len(right)
# Return string formatted based on part lengths
def format(s, first, second):
left, sep, right = s.partition(',')
return left.rjust(first) + sep + right.ljust(second - len(sep))
# Generator yielding part lengths row by row
parts = ((part_lengths(c) for c in r) for r in mylist)
# Combine part lengths to find maximum for each column
# For example data it looks like this: [[5, 3], [4, 4], [1, 2], [1, 2]]
sizes = reduce(lambda x, y: [[max(z) for z in zip(a, b)] for a, b in zip(x, y)], parts)
# Format result based on part lengths
res = [[format(c, *p) for c, p in zip(r, sizes)] for r in mylist]
print(*res, sep='\n')
Output:
[' 10 ', ' 3 ', ' ', ' ']
[' 200 ', '4000,222', '3 ', '1,5']
[' 200,21', ' ', '0,3', '2 ']
['30000 ', ' 4,5 ', '1 ', ' ']
This works for python 2 and 3. I didn't use ljust or rjust though, i just added as many spaces before and after the number as are missing to the maximum sized number in the column:
mylist = [['10', '3', '', ''],
['200', '4000,222', '3', '1,5'],
['200,21', '', '0,3', '2'],
['30000', '4,5', '1', '']]
transposed = list(zip(*mylist))
sizes = [[(x.index(",") if "," in x else len(x), len(x) - x.index(",") if "," in x else 0)
for x in l] for l in transposed]
maxima = [(max([x[0] for x in l]), max([x[1] for x in l])) for l in sizes]
withspaces = [
[' ' * (maxima[i][0] - sizes[i][j][0]) + number + ' ' * (maxima[i][1] - sizes[i][j][1])
for j, number in enumerate(l)] for i, l in enumerate(transposed)]
result = list(zip(*withspaces))
Printing the result in python3:
>>> print(*result, sep='\n')
(' 10 ', ' 3 ', ' ', ' ')
(' 200 ', '4000,222', '3 ', '1,5')
(' 200,21', ' ', '0,3', '2 ')
('30000 ', ' 4,5 ', '1 ', ' ')
How to convert
[('a',1),('b',3)]
to
[('a','1'),('b','3')]
My end goal is to get:
['a 1','b 3']
I tried:
[' '.join(col).strip() for col in [('a',1),('b',3)]]
and
[' '.join(str(col)).strip() for col in [('a',1),('b',3)]]
This ought to do it:
>>> x = [('a',1),('b',3)]
>>> [' '.join(str(y) for y in pair) for pair in x]
['a 1', 'b 3']
If you want to avoid the list comprehensions in jme's answer:
mylist = [('a',1),('b',3)]
map(lambda xs: ' '.join(map(str, xs)), mylist)
puzzle = [[' 1', ' 2', ' 3', ' 4'], [' 5', ' 6', ' 7', ' 8'], [' 9', '10', '11', '12'], ['13', '14', '15', 'X']]
remaining = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
for line in puzzle:
for element in line:
current_line = str(puzzle.index(line))
current_element = str(element)
curr_input = str(input('Enter number for row ' + current_line + ' and column' + current_element + " from " + str(remaining) + "\n\n"))
puzzle[puzzle.index(line), element] = curr_input
remaining.remove(curr_input)
I get the error:
TypeError: list indices must be integers, not tuple
for line
puzzle[puzzle.index(line), element] = curr_input
But neither of those indices are tuples! That is why I use the puzzle.index function! What is going wrong?
You're trying to access the index of a list basing on a tuple index:
puzzle[puzzle.index(line), element] = curr_input
you should use:
puzzle[puzzle.index(line)][line.index(element)] = curr_input
The error is because the way you tried to access is a implicit convertion to a tuple.
edit:
for clarification, just go on your python and try:
>>> 1,2
(1, 2)
Your Error is in this line
puzzle[puzzle.index(line), element] = curr_input
you cant access the element of list of list like that...
This question already has answers here:
How do I make a flat list out of a list of lists?
(34 answers)
Closed 9 years ago.
If you had a long list of lists in the format [['A',1,2],['B',3,4]] and you wanted to combine it into ['A, 1, 2', 'B, 3, 4'] is there a easy list comprehension way to do so?
I do it like this:
this_list = [['A',1,2],['B',3,4]]
final = list()
for x in this_list:
final.append(', '.join([str(x) for x in x]))
But is this possible to be done as a one-liner?
Thanks for the answers. I like the map() based one. I have a followup question - if the sublists were instead of the format ['A',0.111,0.123456] would it be possible to include a string formatting section in the list comprehension to truncate such as to get out 'A, 0.1, 0.12'
Once again with my ugly code it would be like:
this_list = [['A',0.111,0.12345],['B',0.1,0.2]]
final = list()
for x in this_list:
x = '{}, {:.1f}, {:.2f}'.format(x[0], x[1], x[2])
final.append(x)
I solved my own question:
values = ['{}, {:.2f}, {:.3f}'.format(c,i,f) for c,i,f in values]
>>> lis = [['A',1,2],['B',3,4]]
>>> [', '.join(map(str, x)) for x in lis ]
['A, 1, 2', 'B, 3, 4']
You can use nested list comprehensions with str.join:
>>> lst = [['A',1,2],['B',3,4]]
>>> [", ".join([str(y) for y in x]) for x in lst]
['A, 1, 2', 'B, 3, 4']
>>>
li = [['A',1,2],['B',3,4],['A',0.111,0.123456]]
print [', '.join(map(str,sli)) for sli in li]
def func(x):
try:
return str(int(str(x)))
except:
try:
return '%.2f' % float(str(x))
except:
return str(x)
print map(lambda subli: ', '.join(map(func,subli)) , li)
return
['A, 1, 2', 'B, 3, 4', 'A, 0.111, 0.123456']
['A, 1, 2', 'B, 3, 4', 'A, 0.11, 0.12']