Join tuples inside list - python

I have:
mylist = [(['a', 'b'], [1, 2]), (['c', 'd'], [3])]
I need one list with the letters and one with the numbers, like this:
(['a', 'b', 'c', 'd'], [1, 2, 3])
I have made some efforts, but I could just get one list with the letters, not both:
answer = [item for sublist in mylist for item in sublist[0]]
#returns ['a', 'b', 'c', 'd']

answer = [[item for sublist in mylist for item in sublist[i]] for i in range(2)]
Just need to iterate through your sublist :)

Here's a simple alternative using zip and itertools.chain:
from itertools import chain
[list(chain.from_iterable(i)) for i in zip(*mylist)]
# [['a', 'b', 'c', 'd'], [1, 2, 3]]

zip works as well:
tuple(map(lambda x: x[0]+x[1], zip(mylist[0], mylist[1])))
Code:
mylist = [(['a', 'b'], [1, 2]), (['c', 'd'], [3])]
print(tuple(map(lambda x: x[0]+x[1], zip(mylist[0], mylist[1]))))
# (['a', 'b', 'c', 'd'], [1, 2, 3])

Related

How can I copy each element of a list a distinct, specified number of times?

I am using python 3 and I want to create a new list with elements from a the first list repeated as many times as the respective number of the second list
For example:
char = ['a', 'b', 'c']
int = [2, 4, 3]
result = ['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c']
Thx all for help
One-liner solution
Iterate over both lists simultaneously with zip, and create sub-lists for each element with the correct length. Join them with itertools.chain:
# from itertools import chain
list(chain(*([l]*n for l, n in zip(char, int))))
Output:
['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c']
char = ['a', 'b', 'c']
ints = [2, 4, 3]
Solution 1: Using numpy
import numpy as np
result = np.repeat(char, ints)
Solution 2: Pure python
result = []
for i, c in zip(ints, char):
result.extend(c*i)
Output:
['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c']
Using zip
Ex:
c = ['a', 'b', 'c']
intVal = [2, 4, 3]
result = []
for i, v in zip(c, intVal):
result.extend(list(i*v))
print(result)
Output:
['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c']
With for loops, very basic:
results = list()
for k, i in enumerate(integers):
results_to_add = char[k]*i
results.extend(results_to_add)
char = ['a', 'b', 'c']
rep = [2, 4, 3]
res = [c*i.split(",") for i,c in zip(char, rep )] # [['a', 'a'], ['b', 'b', 'b', 'b'], ['c', 'c', 'c']]
print([item for sublist in res for item in sublist]) # flattening the list
EDIT:
one-liner using itertools.chain:
print(list(chain(*[c*i.split(",") for (i,c) in zip(char, int)])))
OUTPUT:
['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c']
One liner using list-comprehension and sum(list_, []).
sum([[x]*y for x,y in zip(char_, int_)], [])
>>> char_ = ['a', 'b', 'c']
>>> int_ = [2, 4, 3]
>>> print(sum([[x]*y for x,y in zip(char_, int_)], []))
>>> ['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c']
Alternative:
list(itertools.chain.from_iterable([[x]*y for x,y in zip(char_, int_)]))
Looks like it is faster than using itertools.
>>> timeit.repeat(lambda:list(itertools.chain.from_iterable([[x]*y for x,y in zip(char_, int_)])), number = 1000000)
[1.2130177360377274, 1.115080286981538, 1.1174913379945792]
>>> timeit.repeat(lambda:sum([[x]*y for x,y in zip(char_, int_)], []), number = 1000000)
[1.0470570910256356, 0.9831087450147606, 0.9912429330288433]

Find the index of supersets for each sublist in another list

I am trying to find the index number in a list of elements that share the same data with elements in another list. These are my lists:
list_A = [['A',1,'a',],['B',2,'b'],['C',3,'c'],['D',4,'d'],['E',5,'e'],['F',6,'f']]
list_B = [['A','a'],['D','d']['E','e']]
And the desired output should be:
[0,3,4]
I've tried using the set()intersection and the the index functions, but I couldn't make 'set' work with the list of lists.
If your list values don't have duplicates, you can convert everything to a set and perform subset checks inside a list comprehension.
set_A = list(map(set, list_A))
set_B = list(map(set, list_B))
# set_B = map(set, list_B) # If you intend to use and throw.
[next((i for i, a in enumerate(set_A) if a.issuperset(b)), None) for b in set_B]
# [0, 3, 4]
For now, if there is no match, next returns the default value you passed to it, in this case - None.
You could do the following:
list_A = [['A', 1, 'a', ], ['B', 2, 'b'], ['C', 3, 'c'], ['D', 4, 'd'], ['E', 5, 'e'], ['F', 6, 'f']]
list_B = [['A', 'a'], ['D', 'd'], ['E', 'e']]
set_B = list(map(set, list_B))
result = [i for i, e in enumerate(list_A) if any(b.intersection(e) for b in set_B)]
print(result)
Output
[0, 3, 4]

How to merge two lists into a list of multiple lists?

Given two lists lst1 and lst2:
lst1 = ['a']
lst2 = [['b'],
['b', 'c'],
['b', 'c', 'd']]
I'd like to merge them into a list of multiple lists with a desired output like this:
desiredList = [['a', ['b']],
['a', ['b', 'c']],
['a', ['b', 'c', 'd']]]
Here is one of my attempts that comes close using lst1 + lst2 and list.append():
lst3 = []
for elem in lst2:
new1 = lst1
new2 = elem
theNew = new1 + new2
lst3.append(theNew)
print(lst3)
#Output:
#[['a', 'b'],
#['a', 'b', 'c'],
#['a', 'b', 'c', 'd']]
Expanding on this, I thought another variation with theNew = new1.append(new2)would do the trick. But no:
lst3 = []
for elem in lst2:
new1 = lst1
new2 = elem
#print(new1 + new2)
#theNew = new1 + new2
theNew = new1.append(new2)
lst3.append(theNew)
print(lst3)
# Output:
[None, None, None]
And you'll get the same result with extend.
I guess this should be really easy, but I'm at a loss.
Thank you for any suggestions!
You could achieve your desired output with itertools.zip_longest with a fillvalue:
>>> from itertools import zip_longest
>>> list(zip_longest(lst1, lst2, fillvalue=lst1[0]))
[('a', ['b']), ('a', ['b', 'c']), ('a', ['b', 'c', 'd'])]
Or if you need a list of lists:
>>> [list(item) for item in zip_longest(lst1, lst2, fillvalue=lst1[0])]
[['a', ['b']], ['a', ['b', 'c']], ['a', ['b', 'c', 'd']]]
Note this assumes that lst1 always contains a single element as in your example.
Or you can use use append, but you need to create new copy of the lst1:
lst3 = []
for elem in lst2:
theNew = lst1[:]
theNew.append(new2)
lst3.append(theNew)
print(lst3)
from itertools import product
list(product(lst1,lst2))
>>>[('a', ['b']), ('a', ['b', 'c']), ('a', ['b', 'c', 'd'])]
[lst1 + [new] for new in lst2]
>>>[['a', ['b']], ['a', ['b', 'c']], ['a', ['b', 'c', 'd']]]
This might help
desiredlist = list(map(lambda y:[lst1,y],lst2))

Sequence numbers for lists with lists

I am preparing a list of lists. the initial list can contain any number of entries but the sub-lists each contain 3 entries, eg:
colony = [['A', 'B', 'C'], [1, 'b', 'c'], [2, 'b', 'c'], [3, 'b', 'c'], [4, 'b', 'c'], [5, 'b', 'c']]
The first entry in each of the sub-lists is the sequence number of the entry and needs to be sequential,
ie. 1, 2, 3, 4, 5, 6,...
A, B and C are the column headings, the data is in the subsequent lists. My difficulty is that if the number of sub-lists that I need to add is say 5, then the sequence number of every entry is 5.How can I change my code to insert the correct sequence number in each sub-list:
colony = [['A', 'B', 'C']]
add_colony = [0, 0, 0]
R = 5
i = 1
for i in range(R):
add_colony[0] = i + 1
add_colony[1] = 'b'
add_colony[2] = 'c'
colony.append(add_colony)
i = i + 1
print()
print('colony = ', colony)
produces:
colony = [['A', 'B', 'C'], [5, 'b', 'c'], [5, 'b', 'c'], [5, 'b', 'c'], [5, 'b', 'c'], [5, 'b', 'c']]
not:
colony = [['A', 'B', 'C'], [1, 'b', 'c'], [2, 'b', 'c'], [3, 'b', 'c'], [4, 'b', 'c'], [5, 'b', 'c']]
I have tried all sorts of variations but end up with the incorrect output.
Thanks in advance
Bob
You are permanently mutating and appending the same list object add_colony. All the lists in colony are references to this same object. You have to create a new list for each loop iteration:
for i in range(R):
add_colony = [0, 0, 0] # without this line ...
add_colony[0] = i + 1 # ... this mutation will affect all the references in colony
add_colony[1] = 'b'
add_colony[2] = 'c'
colony.append(add_colony)
Or shorter:
for i in range(R):
colony.append([i + 1, 'b', 'c'])
Hello there fellow University of Melbourne Student!
As #schwobaseggl mentioned, you need to create a new list object on each iteration of your loop, or you just keep appending the same object over and over again. You could also just make add_colony have the default values ['b', 'c'], and insert() the new i value at the beginning each of the list.
Here is an example:
colony = [['A', 'B', 'C']]
R = 5
for i in range(R):
add_colony = ['b', 'c']
add_colony.insert(0, i+1)
colony.append(add_colony)
print('colony = ', colony)
Which Outputs:
colony = [['A', 'B', 'C'], [1, 'b', 'c'], [2, 'b', 'c'], [3, 'b', 'c'], [4, 'b', 'c'], [5, 'b', 'c']]
You could also use a list comprehension:
colony = [['A', 'B', 'C']] + [[i + 1] + ['b', 'c'] for i in range(R)]
Good Luck!
1 liner list comp that mutates the original list without saving it to a variable (kinda weird):
[colony.append([i, 'b', 'c']) for i in range(1, R + 1)]
print(colony) outputs
[['A', 'B', 'C'], [1, 'b', 'c'], [2, 'b', 'c'], [3, 'b', 'c'], [4, 'b', 'c'], [5, 'b', 'c']]

Unpack a nested list

My question is simple.
There are two lists.
The first is a list of integers:
a = [1, 2, 3]
The other is a list of lists:
b = [['a', 'b'], ['c', 'd'], ['e', 'f']]
How could I get the result below:
result = [[1, 'a', 'b'], [2, 'c', 'd'], [3, 'e', 'f']]
Thanks.
>>> a = [1, 2, 3]
>>> b = [['a', 'b'], ['c', 'd'], ['e', 'f']]
>>> [[aa] + bb for aa, bb in zip(a, b)]
[[1, 'a', 'b'], [2, 'c', 'd'], [3, 'e', 'f']]
In Python3
>>> a = [1, 2, 3]
>>> b = [['a', 'b'], ['c', 'd'], ['e', 'f']]
>>> [aa+bb for *aa, bb in zip(a,b)]
[[1, 'a', 'b'], [2, 'c', 'd'], [3, 'e', 'f']]
Another way to do this would be:
index = 0
l = b
for i in a:
l[index].append(i)
index += 1
The following Python code will unpack each list and assemble it in the form you indicated.
[[a[i]] + b[i] for i in range(min(len(a),len(b)))]
Using Python's enumerate function you can loop over a list with an index. Using x.extend(y) will prepend the values in list x to list y.
a = [1, 2, 3]
b = [['a', 'b'], ['c', 'd'], ['e', 'f']]
result = []
for index, value in enumerate(a):
aa = [value]
aa.extend(b[index])
result.append(aa)

Categories