Cyclic combination of two list of different length - python

I have two list:
list1 = ['a','b','c']
list2 = ['1','2','3','4','5']
and I want to make the list:
list3 = [('1','a'),('2','b'),('3','c'),('4','a'),('5','b')]
In other words, do a cyclic combination between them. So, my question is: Which is the more efficient way to do that?

>>> from itertools import cycle
>>> list1 = ['a','b','c']
>>> list2 = ['1','2','3','4','5']
>>> zip(list2, cycle(list1))
[('1', 'a'), ('2', 'b'), ('3', 'c'), ('4', 'a'), ('5', 'b')]
As some have mentioned in the comments, if you want to cycle both lists and take the first n elements you can do that with,
>>> from itertools import islice, izip
>>> list(islice(izip(cycle(list2), cycle(list1)), 5))
[('1', 'a'), ('2', 'b'), ('3', 'c'), ('4', 'a'), ('5', 'b')]

Here's an alternative approach: A generator that continues the cyclic combination forever:
def cc(l1, l2):
i=0
c1 = len(l1)
c2 = len(l2)
while True:
yield (l1[i % c1], l2[i % c2])
i += 1
The literal answer to your question is then:
x=cc(list2, list1)
[next(x) for i in range(max(len(list1), len(list2)))]
[('1', 'a'), ('2', 'b'), ('3', 'c'), ('4', 'a'), ('5', 'b')]
But you now have a flexible foundation from which to derive all sorts of other interesting bits.

Related

two list integer combine together in python

I am trying to get integers value from a list of specific functions in a two different list and then try to store both list integer with combination of 2nd list integer.
let suppose we have two list,
list1 = ['A(0)','B(1)','C(3)','Z(4)','Z(7)','Z(2)', 'X(3)','X(2)',...]
list2 = ['A(0)','B(1)','C(3)','Z(7)','Z(3)','Z(5)', 'X(11)','X(4)',...]
now only the integer of Z from list1 and list2 will extract and store like this sequence,
Z1 = A(4,7)
Z1 = A(7,3)
Z2 = B(2,5)
first element of list1 and 2nd element of list2 in a sequence.
here is my code which i tried,
for line in list1:
if 'OUTPUT' in line:
print(line.split('Z(')[1].split(')')[0].strip())
for line in list2:
if 'OUTPUT' in line:
print(line.split('Z(')[1].split(')')[0].strip())
here is output
4 7 7 3 2 5
but still i didnt get value like,
Z1 = A(4,7)
Z1 = A(7,3)
Z2 = B(2,5)
def format_list(lst):
new = []
for sub in lst:
open_p = sub.index("(")
close_p = sub.index(")")
letter = sub[:open_p]
number = sub[open_p + 1 : close_p]
new.append((letter, number))
return new
list1 = ["A(0)", "B(1)", "C(3)", "Z(4)", "Z(7)", "Z(2)", "X(3)", "X(2)"]
list2 = ["A(0)", "B(1)", "C(3)", "Z(7)", "Z(3)", "Z(5)", "X(11)", "X(4)"]
lst1 = format_list(list1)
lst2 = format_list(list2)
The above code will format the lists as so:
lst1 = [('A', '0'), ('B', '1'), ('C', '3'), ('Z', '4'), ('Z', '7'), ('Z', '2'), ('X', '3'), ('X', '2')]
lst2 = [('A', '0'), ('B', '1'), ('C', '3'), ('Z', '7'), ('Z', '3'), ('Z', '5'), ('X', '11'), ('X', '4')]
From there, you'll be able to use filter() to find the places in which the numbers differentiate:
different_obj = list(filter(lambda x: x[0][1] != x[1][1], zip(lst1, lst2)))
print(different_obj)
Or if you rather, you don't need to use filter:
different_obj = []
for x, y in zip(lst1, lst2):
if x[1] != y[1]:
different_obj.append((x, y))
outputs:
[(('Z', '4'), ('Z', '7')),
(('Z', '7'), ('Z', '3')),
(('Z', '2'), ('Z', '5')),
(('X', '3'), ('X', '11')),
(('X', '2'), ('X', '4'))]
From there you should be able to organize different_obj to your goal.

Remove tuples with same elements in two lists

a=['-a', ('-c', 'd'), ('-d', 'c')]
b=['-b', ('c', '-d'), ('d', '-c')]
Basicly, for each list, if there is some tuple in another list that has the same elements with it, then remove all of those tuples have this elements from both lists.
(I was using sets instead of tuples, but somewhere in my code got an error
says: unhashable type: 'set', so I changed it to tuples...)
res=[]
for i in a:
for j in b:
if type(i) == tuple and type(j) == tuple:
if i[0] in j and i[1] in j:
res.append(i)
res.append(j)
a,b=list(set(a)-set(res)),list(set(b)-set(res))
print(a,b)
This gives a=['a'],b=['-b'], is there better methods (maybe some simple build in function) to do the same thing ?
More examples
>>>a=['-a', ('-c', 'd'), ('-d', 'c'), ('-d', 'c')]
>>>b=['-b', ('c', '-d'), ('d', '-c'), ('-d', 'c')]
>a=['a'],b=['-b']
>>>a=['-a', ('a', 'b'),('-c', 'd'), ('-d', 'c'), ('-d', 'c')]
>>>b=['-b', ('c', '-d'), ('d', '-c'), ('-d', 'c')]
>a=['a',('a', 'b')],b=['-b']
Use frozenset On the sub items and you will be able to use set.difference:
a = ['-a', ('a', 'b'),('-c', 'd'), ('-d', 'c'), ('-d', 'c')]
b = ['-b', ('c', '-d'), ('d', '-c'), ('-d', 'c')]
seta = {frozenset(i) if isinstance(i, tuple) else i for i in a}
setb = {frozenset(i) if isinstance(i, tuple) else i for i in b}
print(seta - setb, setb - seta)
Prints:
{'-a', frozenset({'a', 'b'})} {'-b'}
I only say this because you said you were using sets before but had issues. You can always turn the frozen sets back to tuple.
Please find the following answer. Basically, you just need to find out duplicates first.
a = ['-a', ('-c', 'd'), ('-d', 'c')]
b = ['-b', ('-c', 'd'), ('d', '-c')]
to_remove = set(a).intersection(set(b))
a = [i for i in a if i not in to_remove or type(i) != tuple]
b = [j for j in b if j not in to_remove or type(j) != tuple]
print a, b

Printing a list of tuples without square brackets in Python

I am attempting to print out a list of tuples without square brackets whilst maintaining parentheses around the tuple.
For example, instead of the output being (current output):
[('1', '3'), ('1', '4'), ('2', '3'), ('2', '4')]
The output should be:
(1, 3) (1, 4) (2, 3) (2, 4)
Current source code below.
from itertools import product
if __name__ == '__main__':
input_lists = []
num_loops = int(input())
i = 0
while i < num_loops:
add_to_list = input()
input_lists.append(add_to_list.split(" "))
i += 1
result = ([i for i in product(*input_lists)])
print(''.join(str(result)))
List comprehension, str.format and str.join:
In [1045]: lst = [('1', '3'), ('1', '4'), ('2', '3'), ('2', '4')]
In [1046]: ' '.join('({}, {})'.format(i, j) for i, j in lst)
Out[1046]: '(1, 3) (1, 4) (2, 3) (2, 4)'
I suggest the int conversion and then unpack:
>>> from __future__ import print_function # for Python 2
>>> lst = [('1', '3'), ('1', '4'), ('2', '3'), ('2', '4')]
>>> print(*[tuple(map(int,t)) for t in lst])
(1, 3) (1, 4) (2, 3) (2, 4)
print(' '.join([str(int(i for i in tup)
for tup in list_of_tuples]))
Calling str() on a tuple produces the tuple itself, really, so I just did this for each item in the list. I also needed to make each item in the tuple an int so I also performed int() on each item in each tuple. The ' '.join() method will separate all of the items in the iterable passed in by a single whitespace. So... I passed in a list comprehension which performs str() on each item in the list.
Here's my take:
print(' '.join([str(tuple(map(int, i))) for i in L]))
A couple of points:
We use tuple with map to convert values from str to int.
str.join is one of the few instances where passing a list is more efficient than generator comprehension.
You can unpack the list.
lst = [(1, 2), (3, 4)]
print(*lst)
Output:
(1, 2) (3, 4)
With an array like
x = [('1', '3'), ('1', '4'), ('2', '3'), ('2', '4')]
you can do simply:
l = [(int(x),int(y)) for x,y in l]
print(*l)
Its output is similar to
output//(1, 3) (1, 4) (2, 3) (2, 4)

Combinations of Nested Lists

I have three lists that are generated by other functions. Let's assume for now they are:
x = ['d', 'e']
g = ['1', '2']
y = ['f', g]
As you can see, g is part of y. I am trying to get all combinations of the elements of the three lists. I have tried going about this in two ways:
One way:
l = []
l.append([a]+[b] for a in x for b in y)
Another way using itertools:
import itertools
l = list(itertools.product([a for a in x], [b for b in y]))
Both ways produce the following combinations:
[('d', 'f'), ('d', ['1', '2']), ('e', 'f'), ('e', ['1', '2'])]
But what I would like to get is:
[('d', 'f'), ('d', '1'), ('d','2'), ('e', 'f'), ('e', '1'), ('e','2')]
Also, when x for example is empty, I get no combinations at all when I am still expecting to get the element combinations of the remaining two lists.
As #BrenBarn commented, you can flatten list y with chain function, and then use product:
from itertools import product, chain
list(product(x, chain.from_iterable(y)))
# [('d', 'f'), ('d', '1'), ('d', '2'), ('e', 'f'), ('e', '1'), ('e', '2')]
This is inspired from #Psidoms answer but just uses a specifically tailored flatten function to make sure only items that should be flattened are iterated:
def flatten(x, types=list):
lst = []
for item in x:
if isinstance(item, types):
for subitem in item:
lst.append(subitem)
else:
lst.append(item)
return lst
>>> from itertools import product
>>> list(product(x, flatten(y)))
[('d', 'f'), ('d', '1'), ('d', '2'), ('e', 'f'), ('e', '1'), ('e', '2')]
Note that there is unfortunatly no such flatten function in the standard library but you could also use one from an external library, for example iteration_utilities.deepflatten. Note that this requires to provide str or basestring as ignore:
>>> from iteration_utilities import deepflatten
>>> list(product(x, deepflatten(y, ignore=str)))
[('d', 'f'), ('d', '1'), ('d', '2'), ('e', 'f'), ('e', '1'), ('e', '2')]
To exclude empty iterables from the product simply exclude empty subiterables. For example:
>>> x = []
>>> iterables = [subiterable for subiterable in (x, list(deepflatten(y, ignore=str))) if subiterable]
>>> list(product(*iterables))
[('f',), ('1',), ('2',)]
I would like to point out two implementations for flatten-like functions available in more_itertools (install via pip install more_itertools).
flatten is an itertools recipe and emulates #Psidom's proposal:
import itertools as it
import more_itertools as mit
list(it.product(x, mit.flatten(y)))
# [('d', 'f'), ('d', '1'), ('d', '2'), ('e', 'f'), ('e', '1'), ('e', '2')]
However, for flattening more deeply nested iterables, consider using collapse:
# Example
x = ['d', 'e']
g = [('1'), [[['2']]]]
y = [{'f'}, g]
# Bad
list(it.product(x, mit.flatten(y)))
# [('d', 'f'), ('d', '1'), ('d', [[['2']]]), ('e', 'f'), ('e', '1'), ('e', [[['2']]])]
# Good
list(it.product(x, mit.collapse(y)))
# [('d', 'f'), ('d', '1'), ('d', '2'), ('e', 'f'), ('e', '1'), ('e', '2')]

Removing duplicates from tuples within a list

I have a list of tuples:
lst = [('a','b'), ('c', 'b'), ('a', 'd'), ('e','f'), ('a', 'b')]
I want the following output list:
output = [('a','b'), ('e','f')]
i.e I want to compare the elements of first tuple with remaining tuples and remove the tuple which contains either one or more duplicate elements.
My attempt:
I was thinking of using for loops, but that wont be feasible once i have very large list. I browsed through following posts but could not get the right solution:
Removing duplicates members from a list of tuples
How do you remove duplicates from a list in whilst preserving order?
If somebody could guide me the right direction, it will be very helpful. Thanks!
Assuming that you want "duplicates" of all elements to be suppressed, and not just the first one, you could use:
lst = [('a','b'), ('c', 'b'), ('a', 'd'), ('e','f'), ('a', 'b')]
def merge(x):
s = set()
for i in x:
if not s.intersection(i):
yield i
s.update(i)
gives
>>> list(merge(lst))
[('a', 'b'), ('e', 'f')]
>>> list(merge([('a', 'b'), ('c', 'd'), ('c', 'e')]))
[('a', 'b'), ('c', 'd')]
>>> list(merge([('a', 'b'), ('a', 'c'), ('c', 'd')]))
[('a', 'b'), ('c', 'd')]
Sets should help:
>>> s = map(set, lst)
>>> first = s[0]
>>> [first] + [i for i in s if not i & first]
[set(['a', 'b']), set(['e', 'f'])]
Or with ifilterfalse:
>>> from itertools import ifilterfalse
>>> s = map(set, lst)
>>> [first] + list(ifilterfalse(first.intersection, s))
[set(['a', 'b']), set(['e', 'f'])]

Categories

Resources