Multiple Tuple to Two-Pair Tuple in Python? - python

What is the nicest way of splitting this:
tuple = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h')
into this:
tuples = [('a', 'b'), ('c', 'd'), ('e', 'f'), ('g', 'h')]
Assuming that the input always has an even number of values.

zip() is your friend:
t = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h')
zip(t[::2], t[1::2])

[(tuple[a], tuple[a+1]) for a in range(0,len(tuple),2)]

Or, using itertools (see the recipe for grouper):
from itertools import izip
def group2(iterable):
args = [iter(iterable)] * 2
return izip(*args)
tuples = [ab for ab in group2(tuple)]

I present this code based on Peter Hoffmann's answer as a response to dfa's comment.
It is guaranteed to work whether or not your tuple has an even number of elements.
[(tup[i], tup[i+1]) for i in range(0, (len(tup)/2)*2, 2)]
The (len(tup)/2)*2 range parameter calculates the highest even number less or equal to the length of the tuple so it is guaranteed to work whether or not the tuple has an even number of elements.
The result of the method is going to be a list. This can be converted to tuples using the tuple() function.
Sample:
def inPairs(tup):
return [(tup[i], tup[i+1]) for i in range(0, (len(tup)/2)*2, 2)]
# odd number of elements
print("Odd Set")
odd = range(5)
print(odd)
po = inPairs(odd)
print(po)
# even number of elements
print("Even Set")
even = range(4)
print(even)
pe = inPairs(even)
print(pe)
Output
Odd Set
[0, 1, 2, 3, 4]
[(0, 1), (2, 3)]
Even Set
[0, 1, 2, 3]
[(0, 1), (2, 3)]

Here's a general recipe for any-size chunk, if it might not always be 2:
def chunk(seq, n):
return [seq[i:i+n] for i in range(0, len(seq), n)]
chunks= chunk(tuples, 2)
Or, if you enjoy iterators:
def iterchunk(iterable, n):
it= iter(iterable)
while True:
chunk= []
try:
for i in range(n):
chunk.append(it.next())
except StopIteration:
break
finally:
if len(chunk)!=0:
yield tuple(chunk)

Related

All permutations of an array in python

I have an array. I want to generate all permutations from that array, including single element, repeated element, change the order, etc. For example, say I have this array:
arr = ['A', 'B', 'C']
And if I use the itertools module by doing this:
from itertools import permutations
perms = [''.join(p) for p in permutations(['A','B','C'])]
print(perms)
Or using loop like this:
def permutations(head, tail=''):
if len(head) == 0:
print(tail)
else:
for i in range(len(head)):
permutations(head[:i] + head[i+1:], tail + head[i])
arr= ['A', 'B', 'C']
permutations(arr)
I only get:
['ABC', 'ACB', 'BAC', 'BCA', 'CAB', 'CBA']
But what I want is:
['A', 'B', 'C',
'AA', 'AB', 'AC', 'BB', 'BA', 'BC', 'CA', 'CB', 'CC',
'AAA', 'AAB', 'AAC', 'ABA', 'ABB', 'ACA', 'ACC', 'BBB', 'BAA', 'BAB', 'BAC', 'CCC', 'CAA', 'CCA'.]
The result is all permutations from the array given. Since the array is 3 element and all the element can be repetitive, so it generates 3^3 (27) ways. I know there must be a way to do this but I can't quite get the logic right.
A generator that would generate all sequences as you describe (which has infinite length if you would try to exhaust it):
from itertools import product
def sequence(xs):
n = 1
while True:
yield from (product(xs, repeat=n))
n += 1
# example use: print first 100 elements from the sequence
s = sequence('ABC')
for _ in range(100):
print(next(s))
Output:
('A',)
('B',)
('C',)
('A', 'A')
('A', 'B')
('A', 'C')
('B', 'A')
('B', 'B')
('B', 'C')
('C', 'A')
('C', 'B')
('C', 'C')
('A', 'A', 'A')
('A', 'A', 'B')
('A', 'A', 'C')
('A', 'B', 'A')
...
Of course, if you don't want tuples, but strings, just replace the next(s) with ''.join(next(s)), i.e.:
print(''.join(next(s)))
If you don't want the sequences to exceed the length of the original collection:
from itertools import product
def sequence(xs):
n = 1
while n <= len(xs):
yield from (product(xs, repeat=n))
n += 1
for element in sequence('ABC'):
print(''.join(element))
Of course, in that limited case, this will do as well:
from itertools import product
xs = 'ABC'
for s in (''.join(x) for n in range(len(xs)) for x in product(xs, repeat=n+1)):
print(s)
Edit: In the comments, OP asked for an explanation of the yield from (product(xs, repeat=n)) part.
product() is a function in itertools that generates the cartesian product of iterables, which is a fancy way to say that you get all possible combinations of elements from the first iterable, with elements from the second etc.
Play around with it a bit to get a better feel for it, but for example:
list(product([1, 2], [3, 4])) == [(1, 3), (1, 4), (2, 3), (2, 4)]
If you take the product of an iterable with itself, the same happens, for example:
list(product('AB', 'AB')) == [('A', 'A'), ('A', 'B'), ('B', 'A'), ('B', 'B')]
Note that I keep calling product() with list() around it here, that's because product() returns a generator and passing the generator to list() exhausts the generator into a list, for printing.
The final step with product() is that you can also give it an optional repeat argument, which tells product() to do the same thing, but just repeat the iterable a certain number of times. For example:
list(product('AB', repeat=2)) == [('A', 'A'), ('A', 'B'), ('B', 'A'), ('B', 'B')]
So, you can see how calling product(xs, repeat=n) will generate all the sequences you're after, if you start at n=1 and keep exhausting it for ever greater n.
Finally, yield from is a way to yield results from another generator one at a time in your own generator. For example, yield from some_gen is the same as:
for x in some_gen:
yield x
So, yield from (product(xs, repeat=n)) is the same as:
for p in (product(xs, repeat=n)):
yield p

How to split list of tuples on condition?

I have list of tuples:
my_list = [(1,'a','b','c'), (2,'d','e','f'), (3,'g','h','i'), (1,'j','k','l'), (2,'m','n','o'), (1,'p','q','r'), (2,'s','t','u')]
I need to split it on sublists of tuples starting with a tuple where first item is '1'.
[(1,'a','b','c'), (2,'d','e','f'), (3,'g','h','i')]
[(1,'j','k','l'), (2,'m','n','o')]
[(1,'p','q','r'), (2,'s','t','u')]
You're effectively computing some kind of a "groupwhile" function -- you want to split at every tuple you find starting in a 1. This looks an awful lot like itertools.groupby, and if we keep a tiny bit of global state (the one_count variable in our example) we can re-use the grouping/aggregation logic already built-in to the language to get your desired result.
import itertools
# The inner function is just so that one_count will be initialized only
# as many times as we want to call this rather than exactly once via
# some kind of global variable.
def gen_count():
def _cnt(t, one_count=[0]):
if t[0] == 1:
one_count[0] += 1
return one_count[0]
return _cnt
result = [list(g[1]) for g in itertools.groupby(my_list, key=gen_count())]
A more traditional solution would be to iterate through your example and append intermediate outputs to a result set.
result = []
for i, *x in my_list:
if i==1:
result.append([(i, *x)])
else:
result[-1].append((i, *x))
Try this code. I assume the break is when the first character (1) is found again. I also assume the output is a list.
my_list = [(1,'a','b','c'), (2,'d','e','f'), (3,'g','h','i'), (1,'j','k','l'), (2,'m','n','o'), (1,'p','q','r'), (2,'s','t','u')]
ch = my_list[0][0]
all = []
st = 0
for i, t in enumerate(my_list):
if t[0] == ch:
if i != 0:
all.append(my_list[st:i])
st = i
else:
all.append(my_list[st:i])
print(all)
Output
[
[(1, 'a', 'b', 'c'), (2, 'd', 'e', 'f'), (3, 'g', 'h', 'i')],
[(1, 'j', 'k', 'l'), (2, 'm', 'n', 'o')],
[(1, 'p', 'q', 'r')]
]

Combine lists of tuples by pairs into specific length of new list of tuples

I am newish to Python. I'm trying to combine two lists of tuples pairwise into a single list of tuples, where the tuples are of defined length (let's say 8):
For example,
input:
x = [(0,1,2,3),(4,5,6,7),(8,9,10,11)]
y = [('a','b','c','d'),('e','f','g','h'),('i','j','k','l')]
output:
[('a', 0, 'b', 1, 'c', 2, 'd', 3),
('e', 4, 'f', 5,'g', 6, 'h', 7),
('i', 8, 'j', 9, 'k', 10, 'l', 11)]
I've tried a few different loops that attempt to concatenate the pairwise combination tuples and then add them for a given length, but no luck. See below.
new = []
for n in range(len(x)):
for p in range(len(x[n])):
if p == len(x[n])-1:
new += [(x[n][p],y[n][p])]
for v in range(len(x[n])):
newer += new[v]
else:
new += [(x[n][p],y[n][p])]
The above 'newer' list is not useful, but the 'new' list provides the pairwise combination of tuples that I'm looking for, like I believe merge() would do, at least.
[('a', 0),('b', 1),('c', 2),('d', 3),('e', 4),('f', 5),('g', 6),('h', 7),('i', 8) ('j', 9),('k', 10), ('l', 11)]
I was thinking I could make a sort of window that read across the desired length (in this case four) and concatenated the selection, but have having trouble getting that to work.
Any other solutions are welcome.
Using a buffer:
b = [None] * 8
[tuple(b) for b[::2], b[1::2] in zip(y, x)]
Start by zipping your sub-lists into lists of matched pairs:
pair_list = [list(zip(a, b)) for a, b in zip(x, y) ]
Result:
[[(0, 'a'), (1, 'b'), (2, 'c'), (4, 'd')],
[(5, 'e'), (6, 'f'), (7, 'g'), (8, 'h')],
[(9, 'i'), (10, 'j'), (11, 'k'), (12, 'l')]]
Now, simply flatten the inner lists. You can look up simple flattening as an "exercise for the student", okay?
(Posted solution on behalf of the question author to move it to the answer space).
I ended up getting something to work:
final_list = []
for outer in range(len(a)):
for ele in range(len(a[outer])):
if ele == 0:
slice_start = 0
else:
slice_start += len(b[ele-1])
slice_end = len(b[ele])+slice_start
capture = [target for sublist in a[slice_start:slice_end] for target in sublist]
final_list.append(capture)
final_list = final_list[:len(a)]
Definitely not as beautiful as heap_overflow's answer.

Python, sympy calculating multivariable function

Let us assume that we have two lists:
variables = ['a','b','c'...]
values = [1,2,3...]
and a simple product function:
function = 'a*b*c*...*z'
I tried to do this way (I do realize it is 100% incorrect, but I have no idea how to substitute multiple variables into a sympified expression):
import sympy
y = sympy.sympify(function).evalf(subs={variable:values})
Here's a complete example. You just need zip to mix the two lists. From the documentation :
To perform multiple substitutions at once, pass a list of (old, new)
pairs to subs.
from sympy import sympify
variables = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
values = range(1, len(variables) + 1)
expression = '*'.join(variables)
sub_table = zip(variables, values)
print values
# [1, 2, 3, 4, 5, 6, 7]
print expression
# a*b*c*d*e*f*g
print sub_table
# [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)]
print sympify(expression).subs(sub_table)
# 5040
As a bonus :
you don't need to build an extra dict
you get an exact integer as output from subs(), and not just a float from evalf().

Append all possibilities from sequences with numbers

I have a question that is consuming my brain. Let us suppose that the variable I stores a sequence, and the variable II another one, and the variable III another one too. The variable one will represent the number 1, the next 2 and the next 3; and then I have another key variable with random characters of these 3 sequences. Giving that fact, I can easily translate the characters of this key variable in the correspondent numbers. In the example, x = 'afh', than, it is the same to say that x = '123', because A OR B OR C = 1, and so on.
Now comes the complicated part:
When the key variable x is translated into numbers, each character individually, I can also return characters randomly from the result. For example: x = '123', then I can return a list like ['a','e','f'], or ['b','d','i'], especially if I use random.choice(). From this, what I couldn't figure out how to do yet is:
How can I append into a list ALL THE POSSIBLE VARIATIONS from the variables I, II, III. For example:
['adg','beh','cfi','aei','ceg',...]
I know how to print endlessly random combinations, but in this case, I get repetitions, and I don't want them. I want to append to a list exactly all the possible variations between I, II and III, because when they're translated into numbers, I can return any character from the correspondent sequence. Well, I hope my example is self-explainable. I thank you all very much for the attention!
I = 'abc' # 1
II = 'def' # 2
III = 'ghi' # 3
x = 'afh' # Random possibility: It could be an input.
L = []
LL = []
for i in range(len(x)):
if x[i] in I:
L.append(1)
if x[i] in II:
L.append(2)
if x[i] in III:
L.append(3)
for i in range(len(L)): # Here lies the mistery...
if L[i] == 1:
LL.append(I)
if L[i] == 2:
LL.append(II)
if L[i] == 3:
LL.append(III)
print L
print LL
The output is:
[1, 2, 3]
['abc', 'def', 'ghi']
Here's how I would rewrite your code. Lengthy if statements like yours are a big code smell. I put the sequences into a tuple and used a single loop. I also replaced the second loop with a list comprehension.
By the way, you could also simplify the indexing if you used zero based indexing like a sensible person.
I = 'abc' # 1
II = 'def' # 2
III = 'ghi' # 3
x = 'afh' # Random possibility: It could be an input.
L = []
LL = []
lists = I, II, III
for c in x:
for i, seq in enumerate(lists):
if c in seq:
L.append(i+1)
LL = [lists[i-1] for i in L]
print L
print LL
Also, be sure to check out the itertools module, and in particular the product function. It's not clear exactly what you mean, but product gives you all combinations of an item from each of a list of sequences.
Thank you very much Antimony! The answer is exactly product() from itertools. The code with it is bloody far more simple:
from itertools import *
I = 'abc' # 1
II = 'def' # 2
III = 'ghi' # 3
IV = product(I,II,III)
for i in IV:
print i
And the output is exactly what I wanted, every possible combination:
('a', 'd', 'g')
('a', 'd', 'h')
('a', 'd', 'i')
('a', 'e', 'g')
('a', 'e', 'h')
('a', 'e', 'i')
('a', 'f', 'g')
('a', 'f', 'h')
('a', 'f', 'i')
('b', 'd', 'g')
('b', 'd', 'h')
('b', 'd', 'i')
('b', 'e', 'g')
('b', 'e', 'h')
('b', 'e', 'i')
('b', 'f', 'g')
('b', 'f', 'h')
('b', 'f', 'i')
('c', 'd', 'g')
('c', 'd', 'h')
('c', 'd', 'i')
('c', 'e', 'g')
('c', 'e', 'h')
('c', 'e', 'i')
('c', 'f', 'g')
('c', 'f', 'h')
('c', 'f', 'i')
python 3.2
[(i,v,c) for i in I for v in II for c in III]

Categories

Resources