Related
I have a huge list of tuples each containing another two tuples like e.g.
lst = [((0,2,1), (2,1,3)), ((3,2,1), (0,1,1)), ...]
Many of the elements of this list are not acceptable under certain criteria and I am trying to create a new list composed by those elements satisfying those conditions. Among others, I would like to remove those elements whose left (resp. right) tuple contains a zero but the right (resp. left) tuple has no zero in the same position. Also those elements whose left tuple contains two consecutive non zero numbers (in a given range) and the number located in the right tuple in the same position than the one where the repetition appears is not a 1. To do this, I have tried:
acceptable_lst = [elem for elem in lst for j in range(3) if not ((elem[0][j] == 0 and
elem[1][j] != 0) or (j < 2 and elem[0][j] != 0 and elem[0][j] == elem[0][j+1]
and elem[1][j+1] != 1)]
When I apply this code to e.g.
lst = [((3,2,2), (1,2,3)),
((0,1,3), (2,2,3)),
((1,1,2), (3,3,3)),
((0,2,2), (3,3,3)),
((2,2,1), (3,1,3))]
I would like to get:
acceptable_lst = [((2,2,1), (3,1,3))]
Why? The first element in lst has a rep of 2 in the left tuple, the second 2 in the third position, but the third element in the right tuple is not a 1. The second element has a zero in the first position of the left tuple and a non zero in the same position of the right tuple, so on ... Only the last element in lst satisfies the above conditions.
However what I get is
[((3, 2, 2), (1, 2, 3)),
((3, 2, 2), (1, 2, 3)),
((0, 1, 3), (2, 2, 3)),
((0, 1, 3), (2, 2, 3)),
((1, 1, 2), (3, 3, 3)),
((1, 1, 2), (3, 3, 3)),
((0, 2, 2), (3, 3, 3)),
((2, 2, 1), (3, 1, 3)),
((2, 2, 1), (3, 1, 3)),
((2, 2, 1), (3, 1, 3))]
which indicates that my code is completely wrong. How can I implement what I need?
Check the validity in a function
def valid(elemLeft, elemRight):
lastItem = None
for i in range(3):
if elemLeft[i] == 0 and elemRight[i] != 0:
return False
if lastItem != None:
if elemLeft[i] == lastItem and elemRight[i] != 1:
return False
lastItem = elemLeft[i]
return True
lst = [((3,2,2),(1,2,3)), ((0,1,3),(2,2,3)), ((1,1,2),(3,3,3)), ((0,2,2),(3,3,3)), ((2,2,1),(3,1,3))]
acceptable_lst = [elem for elem in lst if valid(elem[0],elem[1])]
print(acceptable_lst)
You are doing two for loops in your list comprehension.
[ elem for elem in lst for j in range(3) if condition ]
is equivalent to:
out_list = []
for elem in lst:
for j in range(3):
if condition:
out_list.append(elem)
If you have to use list comprehension for this task, you could modify it:
import numpy as np
acceptable_lst = [elem for elem in lst
if not (np.any([(elem[0][j] == 0 and elem[1][j] != 0) for j in range(3)]))
and not np.any([(j < 2 and elem[0][j] != 0 and elem[0][j] == elem[0][j+1] and elem[1][j+1] != 1) for j in range(3)])]
I want to be able to find all the different ways a set of numbers(x) can be summed into a certain value, y but I'm having trouble even getting the base case right.
For example:
If I have x = set (1,2,3,4,5) and I want to see how many different ways y = 5 can be summed up using numbers from x:
my recursive function would return 7 because:
'''
5
4+1
3+2
3+1+1
2+2+1
2+1+1+1
1+1+1+1+1
'''
def recur(x,y):
if y == x:
v += 1
if y > x:
v += 0
else:
#call recursively
This does not use recursion, but itertools.combinations_with_replacement:
def all_combs(y, x=range(1, 5+1)):
all_combs = []
for i in range(1, y+1):
combs = combinations_with_replacement(x, i)
all_combs.extend([comb for comb in combs if sum(comb) == y])
return all_combs
combs = all_combs(5)
# [(5,), (1, 4), (2, 3), (1, 1, 3), (1, 2, 2), (1, 1, 1, 2), (1, 1, 1, 1, 1)]
num_combs = len(combs) # 7
This is my script.py:
from itertools import product
A = input().split()
B = input().split()
li1 = []
li2 = []
for i in A:
li1.append(int(i))
for j in B:
li2.append(int(j))
result = product(li1,li2)
print(tuple(result))
it gives me result like this ((1, 3), (1, 4), (2, 3), (2, 4))
But I want to result like this (1, 3) (1, 4) (2, 3) (2, 4)
How can I do this ?
Unpack with a *
print(*result)
This will use the contents of the iterable as arguments to print(), instead of the whole thing as a single argument.
"How could I get the indexes of elements in an n-row array configuration?
The length of a row should be given by a string of length l.
For example:
For a 2-row array configuration with l=7, the elements (X) will have indexes:
elements = [(0, 0), (0, 2), (0, 4), (0, 6), (1, 1), (1, 3), (1, 5), (1, 7)]
[[X - X - X - X],
[- X - X - X -]]
For a 3-rows array with l=8, the elements (X) will have indexes:
elements = [(0, 0), (0, 4), (0, 8), (1, 1), (1, 3), (1, 5), (1, 7), (2, 2), (2, 6)]
[[X - - - X - - - X],
[- X - X - X - X -],
[- - X - - - X - -]]
The idea is to extended to higher row numbers. Is there an "analytical" way of getting those indexes?
Thanks in advance.
P.S.: By "analytical" I mean an equation or something that I could code
this is my first shot at your problem:
def grid(width, depth):
assert depth % 2 == 0
height = depth//2 + 1
lines = []
for y in range(height):
line = ''.join('X' if ((i+y) % depth == 0 or (i-y) % depth == 0)
else '-' for i in range(width))
lines.append(line)
return '\n'.join(lines)
the depth is the parameter that defines how far the Xs are spaces on fhe first line (the name is poorly chosen); the width is how many characters should be displayed per line.
this will only work for even depths.
with outputs
-> print(grid(width=10, depth=2))
X-X-X-X-X-
-X-X-X-X-X
-> print(grid(width=10, depth=4))
X---X---X-
-X-X-X-X-X
--X---X---
-> print(grid(width=15, depth=6))
X-----X-----X--
-X---X-X---X-X-
--X-X---X-X---X
---X-----X-----
this was mostly trial & error so there is not much to explain...
if you prefer your elements representation - here is what you can do:
def grid_elements(width, depth):
assert depth % 2 == 0
height = depth//2 + 1
elements = []
for y in range(height):
elements.extend((y, i) for i in range(width)
if ((i+y) % depth == 0 or (i-y) % depth == 0))
return elements
this creates the results:
-> print(grid_elements(width=10, depth=2))
[(0, 0), (0, 2), (0, 4), (0, 6), (0, 8), (1, 1), (1, 3), (1, 5), (1, 7), (1, 9)]
-> print(grid_elements(width=10, depth=4))
[(0, 0), (0, 4), (0, 8), (1, 1), (1, 3), (1, 5), (1, 7), (1, 9), (2, 2), (2, 6)]
-> print(grid_elements(width=15, depth=6))
[(0, 0), (0, 6), (0, 12), (1, 1), (1, 5), (1, 7), (1, 11), (1, 13), (2, 2),
(2, 4), (2, 8), (2, 10), (2, 14), (3, 3), (3, 9)]
This is a example of code that can do this.
import numpy as np
nb_row = 3; nb_column = 10;
separator_element = '-'; element = 'X';
#Initialise the size of the table
table = np.chararray((nb_row, nb_column), itemsize=1);
table[:] = separator_element; #By default, all have the separator element.
#Loop over each column: First column have element at first row. The element
#will after decrease and wrap around the nb of row.
#When at the bottom, switch to go up. At top, switch to go down.
position_element = 0; go_down = 1;
for no_column in xrange(0,nb_column):
table[position_element,no_column] = element;
#Case when go down.
if go_down == 1:
position_element = (position_element+1) % (nb_row);
go_down = (position_element != (nb_row-1)); #Go up after go down.
#Case when go up;
else:
position_element = (position_element-1) % (nb_row);
go_down = (position_element == 0); #Go up after go down.
#end
#end
print(table)
#[['X' '-' '-' '-' 'X' '-' '-' '-' 'X' '-']
#['-' 'X' '-' 'X' '-' 'X' '-' 'X' '-' 'X']
#['-' '-' 'X' '-' '-' '-' 'X' '-' '-' '-']]
We can use itertools.groupby here to create a dictionary that has the
sublist indexes of interest as values and index of sublists as keys {0: [0, 2, 4, 6], 1: [1, 3, 5, 7]}, We can then use this on list that is generated using n = 7. From there we can modify the sublist using the indexes that are values for the corresponding sublist index in our keys.
from itertools import groupby
elements = [(0, 0), (0, 2), (0, 4), (0, 6), (1, 1), (1, 3), (1, 5), (1, 7)]
n = 7
d = {}
for k, g in groupby(elements, key=lambda x: x[0]):
d[k] = [i[1] for i in g]
lst = [['-']*n for i in d]
for k in d:
for i, v in enumerate(lst[k]):
if i in d[k]:
lst[k][i] = 'X'
lst[k] = ' '.join(lst[k])
for i in lst:
print(i)
# X - X - X - X
# - X - X - X -
I have a list as follows:
l = [0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,2,2,2]
I want to determine the length of a sequence of equal items, i.e for the given list I want the output to be:
[(0, 6), (1, 6), (0, 4), (2, 3)]
(or a similar format).
I thought about using a defaultdict but it counts the occurrences of each item and accumulates it for the entire list, since I cannot have more than one key '0'.
Right now, my solution looks like this:
out = []
cnt = 0
last_x = l[0]
for x in l:
if x == last_x:
cnt += 1
else:
out.append((last_x, cnt))
cnt = 1
last_x = x
out.append((last_x, cnt))
print out
I am wondering if there is a more pythonic way of doing this.
You almost surely want to use itertools.groupby:
l = [0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,2,2,2]
answer = []
for key, iter in itertools.groupby(l):
answer.append((key, len(list(iter))))
# answer is [(0, 6), (1, 6), (0, 4), (2, 3)]
If you want to make it more memory efficient, yet add more complexity, you can add a length function:
def length(l):
if hasattr(l, '__len__'):
return len(l)
else:
i = 0
for _ in l:
i += 1
return i
l = [0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,2,2,2]
answer = []
for key, iter in itertools.groupby(l):
answer.append((key, length(iter)))
# answer is [(0, 6), (1, 6), (0, 4), (2, 3)]
Note though that I have not benchmarked the length() function, and it's quite possible it will slow you down.
Mike's answer is good, but the itertools._grouper returned by groupby will never have a __len__ method so there is no point testing for it
I use sum(1 for _ in i) to get the length of the itertools._grouper
>>> import itertools as it
>>> L = [0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,2,2,2]
>>> [(k, sum(1 for _ in i)) for k, i in it.groupby(L)]
[(0, 6), (1, 6), (0, 4), (2, 3)]