Splitting list to many lists with conditions - python

I am having such code to make 4 lists from one with my conditions. It is splitting depends on sign of elements of lists.
Like I want to get list with all positive,list with lists where first elements are positive and second are negative ,etc...And all combination like this.
It is easy to create 4 lists using filter when all lists are containts only 2 elements.
vals=[(0, 0), (0, 1), (0, -1), (1, 0), (1, 1), (1, -1), (-1, 0), (-1, 1), (-1, -1)]
new_f=list(filter(lambda x:x[0]>=0,vals))
new_f=list(filter(lambda x:x[1]>=0,new_f))
print(new_f)
new_f=list(filter(lambda x:x[0]<=0,vals))
new_f=list(filter(lambda x:x[1]>=0,new_f))
print(new_f)
new_f=list(filter(lambda x:x[0]>=0,vals))
new_f=list(filter(lambda x:x[1]<=0,new_f))
print(new_f)
new_f=list(filter(lambda x:x[0]<=0,vals))
new_f=list(filter(lambda x:x[1]<=0,new_f))
print(new_f)
Here is my output:
[(0, 0), (0, 1), (1, 0), (1, 1)]
[(0, 0), (0, 1), (-1, 0), (-1, 1)]
[(0, 0), (0, -1), (1, 0), (1, -1)]
[(0, 0), (0, -1), (-1, 0), (-1, -1)]
But if length of my elements is 3 or more, what can I do not to write all the condionts( there will be 2 ** 3 situations and 2 ** 4 situations for len=4)
For example here is my input for n=3 and example of situation when I want to filter this by "there are no negative" and "first-negative-other not negative"
vals=[(0, 0, 0), (0, 0, 1), (0, 0, -1), (0, 1, 0), (0, 1, 1), (0, 1, -1), (0, -1, 0), (0, -1, 1), (0, -1, -1), (1, 0, 0), (1, 0, 1), (1, 0, -1), (1, 1, 0), (1, 1, 1), (1, 1, -1), (1, -1, 0), (1, -1, 1), (1, -1, -1), (-1, 0, 0), (-1, 0, 1), (-1, 0, -1), (-1, 1, 0), (-1, 1, 1), (-1, 1, -1), (-1, -1, 0), (-1, -1, 1), (-1, -1, -1)]
new_f=list(filter(lambda x:x[0]>=0,vals))
new_f=list(filter(lambda x:x[1]>=0,new_f))
new_f=list(filter(lambda x:x[2]>=0,new_f))
print(new_f)
new_f=list(filter(lambda x:x[0]<=0,vals))
new_f=list(filter(lambda x:x[1]>=0,new_f))
new_f=list(filter(lambda x:x[2]>=0,new_f))
print(new_f)
Here is output:
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (-1, 0, 0), (-1, 0, 1), (-1, 1, 0), (-1, 1, 1)]
So I need some kinds of automatization of this process to use it with longer arrays.

Make a list of lists. The index of each large list is the binary direction of the comparison: 1 or True for positive, 0 or False for negative. Call that the mask.
Iterate through all possible masks, 0 through 2^n-1. For each mask, convert the Boolean vector to a sequence of coefficients. For instance, the mask 9 is binary 1001, a coefficient sequence [1, -1, -1, 1]. Multiply the tuple by the mask; for instance,
(0, 1, -1, 1) * [1, -1, -1, 1] => [0, -1, 1, 1]
Use the all function to filter the entire vector, given the mask and the element from your list of candidates.
all(bit >= 0 for bit in
[element[i] * mask[i] for i in len(element)])
Now, wrap that in a loop the iterates through your mask values. If you're persistent enough, you can create the entire list of 2^n filtered lists in a single line of code, using all and nested comprehensions. I suggest leaving that for late-night hacking, not problem-solving.
Also note that itertools.permutations will be happy to generate masks for you.

You can use itertools.product over the two filter functions with a repeat of the size of the tuples in your input, then zip the filter functions with individual items in each tuple and only output the tuple if all filters are satisfied:
[[t for t in vals if all(f(i) for (f, i) in zip(filters, t))] for filters in product(((0).__le__, (0).__ge__), repeat=len(vals[0]))]
so that given your sample input:
vals = [(0, 0, 0), (0, 0, 1), (0, 0, -1), (0, 1, 0), (0, 1, 1), (0, 1, -1), (0, -1, 0), (0, -1, 1), (0, -1, -1), (1, 0, 0), (1, 0, 1), (1, 0, -1), (1, 1, 0), (1, 1, 1), (1, 1, -1), (1, -1, 0), (1, -1, 1), (1, -1, -1), (-1, 0, 0), (-1, 0, 1), (-1, 0, -1), (-1, 1, 0), (-1, 1, 1), (-1, 1, -1), (-1, -1, 0), (-1, -1, 1), (-1, -1, -1)]
This returns:
[[(0, 0, 0),
(0, 0, 1),
(0, 1, 0),
(0, 1, 1),
(1, 0, 0),
(1, 0, 1),
(1, 1, 0),
(1, 1, 1)],
[(0, 0, 0),
(0, 0, -1),
(0, 1, 0),
(0, 1, -1),
(1, 0, 0),
(1, 0, -1),
(1, 1, 0),
(1, 1, -1)],
[(0, 0, 0),
(0, 0, 1),
(0, -1, 0),
(0, -1, 1),
(1, 0, 0),
(1, 0, 1),
(1, -1, 0),
(1, -1, 1)],
[(0, 0, 0),
(0, 0, -1),
(0, -1, 0),
(0, -1, -1),
(1, 0, 0),
(1, 0, -1),
(1, -1, 0),
(1, -1, -1)],
[(0, 0, 0),
(0, 0, 1),
(0, 1, 0),
(0, 1, 1),
(-1, 0, 0),
(-1, 0, 1),
(-1, 1, 0),
(-1, 1, 1)],
[(0, 0, 0),
(0, 0, -1),
(0, 1, 0),
(0, 1, -1),
(-1, 0, 0),
(-1, 0, -1),
(-1, 1, 0),
(-1, 1, -1)],
[(0, 0, 0),
(0, 0, 1),
(0, -1, 0),
(0, -1, 1),
(-1, 0, 0),
(-1, 0, 1),
(-1, -1, 0),
(-1, -1, 1)],
[(0, 0, 0),
(0, 0, -1),
(0, -1, 0),
(0, -1, -1),
(-1, 0, 0),
(-1, 0, -1),
(-1, -1, 0),
(-1, -1, -1)]]

Related

How do I pop item off a list of tuples, based on the value of the first number in each tuple?

I am trying to create a list of tuples that consists of all the variations of a set of numbers. However I want to remove any variants from the list that are the same sequence but offset by a position or two. For example:
(-1,1,2), (1,2,-1) & (2,-1,1) I would only want the first one.
Here's where I'm up to:
import itertools as it
list = [-1, 0, 1, 2]
cycles = []
list_cycle_3 = it.permutations(cycles, 3)
list_cycle_4 = it.permutations(cycles, 4)
for item in list_cycle_3:
cycles.append(item)
for item in list_cycle_4:
cycles.append(item)
print(cycles)
This results in:
[(-1, 0, 1), (-1, 0, 2), (-1, 1, 0), (-1, 1, 2), (-1, 2, 0), (-1, 2, 1),
(0, -1, 1), (0, -1, 2), (0, 1, -1), (0, 1, 2), (0, 2, -1), (0, 2, 1),
(1, -1, 0), (1, -1, 2), (1, 0, -1), (1, 0, 2), (1, 2, -1), (1, 2, 0),
(2, -1, 0), (2, -1, 1), (2, 0, -1), (2, 0, 1), (2, 1, -1), (2, 1, 0),
(-1, 0, 1, 2), (-1, 0, 2, 1), (-1, 1, 0, 2), (-1, 1, 2, 0), (-1, 2, 0, 1), (-1, 2, 1, 0), (0, -1, 1, 2), (0, -1, 2, 1), (0, 1, -1, 2), (0, 1, 2, -1),
(0, 2, -1, 1), (0, 2, 1, -1), (1, -1, 0, 2), (1, -1, 2, 0), (1, 0, -1, 2),
(1, 0, 2, -1), (1, 2, -1, 0), (1, 2, 0, -1), (2, -1, 0, 1), (2, -1, 1, 0),
(2, 0, -1, 1), (2, 0, 1, -1), (2, 1, -1, 0), (2, 1, 0, -1)]
So what do I do next to filter the results so I only have the results I want, which are:
[(-1, 0, 1), (-1, 0, 2), (-1, 1, 0), (-1, 1, 2), (-1, 2, 0), (-1, 2, 1),
(0, 1, 2), (0, 2, 1), (-1, 0, 1, 2), (-1, 0, 2, 1), (-1, 1, 0, 2),
(-1, 1, 2, 0), (-1, 2, 0, 1), (-1, 2, 1, 0)]
If it helps a simple difference between the lists are that the list I want is all the tuples starting with -1, and the tuples where there is no -1 starting with 0
Start with a list that does not contain the number that you want to filter against:
For example, you'll only need the ones that starts with 0. Then your list is
l = [-1, 1, 2]
Find all the two element permutatations and filter them as you like.
Ant then add 0 as the first element by mapping your result set.
Example:
In [2]: from itertools import permutations
In [3]: l = [-1, 1, 2]
In [4]: p = permutations(l, 2)
In [5]: [(0, *t) for t in p]
Out[5]: [(0, -1, 1), (0, -1, 2), (0, 1, -1), (0, 1, 2), (0, 2, -1), (0, 2, 1)]
You could do a similar trick for, say, the ones that does not have -1 in them and start with 0 which is omit -1 and 0 from your list and then add 0 as the first element into your result sets items.
And do not override reserved keywords in your code:
list = [...] # do not do that
l=[(-1, 0, 1), (-1, 0, 2), (-1, 1, 0), (-1, 1, 2), (-1, 2, 0), (-1, 2, 1),
(0, -1, 1), (0, -1, 2), (0, 1, -1), (0, 1, 2), (0, 2, -1), (0, 2, 1),
(1, -1, 0), (1, -1, 2), (1, 0, -1), (1, 0, 2), (1, 2, -1), (1, 2, 0),
(2, -1, 0), (2, -1, 1), (2, 0, -1), (2, 0, 1), (2, 1, -1), (2, 1, 0),
(-1, 0, 1, 2), (-1, 0, 2, 1), (-1, 1, 0, 2), (-1, 1, 2, 0), (-1, 2, 0, 1), (-1, 2, 1, 0), (0, -1, 1, 2), (0, -1, 2, 1), (0, 1, -1, 2), (0, 1, 2, -1),
(0, 2, -1, 1), (0, 2, 1, -1), (1, -1, 0, 2), (1, -1, 2, 0), (1, 0, -1, 2),
(1, 0, 2, -1), (1, 2, -1, 0), (1, 2, 0, -1), (2, -1, 0, 1), (2, -1, 1, 0),
(2, 0, -1, 1), (2, 0, 1, -1), (2, 1, -1, 0), (2, 1, 0, -1)]
l2=[]
for i in l:
if i[0] == -1 :
l2.append(i)
print(l2)
this code works
output
[(-1, 0, 1), (-1, 0, 2), (-1, 1, 0), (-1, 1, 2), (-1, 2, 0), (-1, 2, 1), (-1, 0, 1, 2), (-1, 0, 2, 1), (-1, 1, 0, 2), (-1, 1, 2, 0), (-1, 2, 0, 1), (-1, 2, 1, 0)]

How to generate all distinct combinations (where input elements are repeated) in Python(using Itertools)?

I have a set of numbers [1, 2, 4, 1]. Now, I want to generate all possible combinations from this set of size k (example k = 3). All the generated output sets must not be duplicate
Example : [1, 2, 1] and [2, 1, 1] are the same sets but they should not be selected. Only one of them should appear. Is it possible using combinations from itertools in Python?
import itertools
x = [1, 2, 1]
print([p for p in itertools.product(x, repeat=3)])
I have tried using itertools.product but it doesnt work and
using combinations from itertools is getting duplicates
I have tried using itertools.combinations
print([p for p in set(itertools.combinations(x, r=3))])
If I give the following input
x = [-1, 0, 1, 2, -1, -4]
The ouput generated for r = 3 is
[(0, -1, -4), (-1, -1, -4), (-1, 1, -4), (0, 2, -1), (-1, 0, 2), (-1, 2, -4), (0, 1, 2), (2, -1, -4), (-1, 0, -1), (0, 1, -4), (1, 2, -4), (-1, 0, 1), (-1, 1, 2), (0, 2, -4), (-1, 1, -1), (-1, 2, -1), (1, 2, -1), (0, 1, -1), (-1, 0, -4), (1, -1, -4)]
(-1, 0, 1) and (0, 1, -1) are duplicate sets with same combinations. I am not sure how to overcome this.
These are called multisets, and we can easily obtain the combinations of these with the sympy module.
from sympy.utilities.iterables import multiset_combinations
list(multiset_combinations([1, 2, 4, 1], 3))
[[1, 1, 2], [1, 1, 4], [1, 2, 4]]
And here is the example by #EdedkiOkoh:
x = [-1, 0, 1, 2, -1, -4]
list(multiset_combinations(x, 3))
[[-4, -1, -1],
[-4, -1, 0],
[-4, -1, 1],
[-4, -1, 2],
[-4, 0, 1],
[-4, 0, 2],
[-4, 1, 2],
[-1, -1, 0],
[-1, -1, 1],
[-1, -1, 2],
[-1, 0, 1],
[-1, 0, 2],
[-1, 1, 2],
[0, 1, 2]]
You can use python's set datatype to remove those duplicates since sets will only contain the unique combinations:
import itertools as it
x = [-1, 0, 1, 2, -1, -4]
permutations = [p for p in set(it.combinations(x, r=3))]
print(permutations)
Output:
[(0, 1, 2),
(-1, 1, -1),
(-1, 2, -1),
(0, -1, -4),
(-1, -1, -4),
(-1, 1, -4),
(-1, 2, -4),
(2, -1, -4),
(1, 2, -4),
(-1, 0, 1),
(1, 2, -1),
(-1, 0, -4),
(-1, 0, 2),
(-1, 0, -1),
(-1, 1, 2),
(0, 2, -4),
(0, 2, -1),
(0, 1, -4),
(1, -1, -4),
(0, 1, -1)]
Then use can use the following line:
unique_permutations = set(tuple(sorted(t)) for t in permutations)
Output:
{(-4, -1, -1),
(-4, -1, 0),
(-4, -1, 1),
(-4, -1, 2),
(-4, 0, 1),
(-4, 0, 2),
(-4, 1, 2),
(-1, -1, 0),
(-1, -1, 1),
(-1, -1, 2),
(-1, 0, 1),
(-1, 0, 2),
(-1, 1, 2),
(0, 1, 2)}
What about getting the combinations and then taking only the unique ones by keying a dictionary with the frozenset result of the combinations. This will only use generators until creating the dictionary.
combs1, combs2 = itertools.tee(itertools.combinations(x, r=3))
res = list(dict(zip(map(frozenset, combs1), combs2)).values())

Generating all possibly length n combinations of two items in python

I am trying to generate a list of length n from two possible items. e.g. One example could be, a list of length 4 comprising zeros or ones which would be 0000, 0001, 0010, 0100, 1000, 1001, etc.
Thanks in advance,
Jack
With itertools.product:
In [1]: from itertools import product
In [2]: list(product((0, 1), repeat=4))
Out[2]:
[(0, 0, 0, 0),
(0, 0, 0, 1),
(0, 0, 1, 0),
(0, 0, 1, 1),
(0, 1, 0, 0),
(0, 1, 0, 1),
(0, 1, 1, 0),
(0, 1, 1, 1),
(1, 0, 0, 0),
(1, 0, 0, 1),
(1, 0, 1, 0),
(1, 0, 1, 1),
(1, 1, 0, 0),
(1, 1, 0, 1),
(1, 1, 1, 0),
(1, 1, 1, 1)]
You can also just print ints as binary strings:
In [3]: for i in range(2**4):
...: print('{:04b}'.format(i))
...:
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
Check out the product function from the itertools module: https://docs.python.org/2/library/itertools.html#itertools.product
from itertools import product
product(range(2), repeat=4)
# --> <itertools.product object at 0x10bdc1500>
list(product(range(2), repeat=4))
# --> [(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 1, 0), (0, 0, 1, 1), (0, 1, 0, 0), (0, 1, 0, 1), (0, 1, 1, 0), (0, 1, 1, 1), (1, 0, 0, 0), (1, 0, 0, 1), (1, 0, 1, 0), (1, 0, 1, 1), (1, 1, 0, 0), (1, 1, 0, 1), (1, 1, 1, 0), (1, 1, 1, 1)]

python all possible combinations of 0,1 of length k

I need all possible combinations of 0,1 of length k.
Suppose k=2 I want (0,0), (0,1), (1,0), (1,1)
I have tried different function in itertools but I did not find what I want.
>>> list(itertools.combinations_with_replacement([0,1], 2))
[(0, 0), (0, 1), (1, 1)]
>>> list(itertools.product([0,1], [0,1])) #does not work if k>2
[(0, 0), (0, 1), (1, 0), (1, 1)]
itertools.product() takes a repeat keyword argument; set it to k:
product(range(2), repeat=k)
Demo:
>>> from itertools import product
>>> for k in range(2, 5):
... print list(product(range(2), repeat=k))
...
[(0, 0), (0, 1), (1, 0), (1, 1)]
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
[(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 1, 0), (0, 0, 1, 1), (0, 1, 0, 0), (0, 1, 0, 1), (0, 1, 1, 0), (0, 1, 1, 1), (1, 0, 0, 0), (1, 0, 0, 1), (1, 0, 1, 0), (1, 0, 1, 1), (1, 1, 0, 0), (1, 1, 0, 1), (1, 1, 1, 0), (1, 1, 1, 1)]

product of variable number of range(n)'s

I am trying to understand how to write code that will output all the divisors of a number. The approach that I am most interested in taking begins with a function that returns a dictionary where the keys are the prime divisors and the values are the number of times divisible. I have already written this function like so:
def div_pair(num):
divPair = {}
for prime in prime_gen():
primeDegree = 0
while num % prime == 0:
num = int(num / prime)
primeDegree += 1
if primeDegree > 0:
divPair[prime] = primeDegree
if num == 1:
return divPair
As an example, the number 84,000 outputs the dictionary
{2: 5, 3: 1, 5: 3, 7: 1}
What I want to do from here is generate powersets(?) of any given values returned by the different numbers divPair would return, and then multiply these powersets by their matched primes. This is an example which uses the kind of code I am trying to use to generate the powersets:
from itertools import product
list(product(range(5+1), range(1+1), range(3+1), range(1+1)))
Outputs this:
[(0, 0, 0, 0),
(0, 0, 0, 1),
(0, 0, 1, 0),
(0, 0, 1, 1),
(0, 0, 2, 0),
(0, 0, 2, 1),
(0, 0, 3, 0),
(0, 0, 3, 1),
(0, 1, 0, 0),
(0, 1, 0, 1),
(0, 1, 1, 0),
(0, 1, 1, 1),
(0, 1, 2, 0),
(0, 1, 2, 1),
(0, 1, 3, 0),
(0, 1, 3, 1),
(1, 0, 0, 0),
(1, 0, 0, 1),
(1, 0, 1, 0),
(1, 0, 1, 1),
(1, 0, 2, 0),
(1, 0, 2, 1),
(1, 0, 3, 0),
(1, 0, 3, 1),
(1, 1, 0, 0),
(1, 1, 0, 1),
(1, 1, 1, 0),
(1, 1, 1, 1),
(1, 1, 2, 0),
(1, 1, 2, 1),
(1, 1, 3, 0),
(1, 1, 3, 1),
(2, 0, 0, 0),
(2, 0, 0, 1),
(2, 0, 1, 0),
(2, 0, 1, 1),
(2, 0, 2, 0),
(2, 0, 2, 1),
(2, 0, 3, 0),
(2, 0, 3, 1),
(2, 1, 0, 0),
(2, 1, 0, 1),
(2, 1, 1, 0),
(2, 1, 1, 1),
(2, 1, 2, 0),
(2, 1, 2, 1),
(2, 1, 3, 0),
(2, 1, 3, 1),
(3, 0, 0, 0),
(3, 0, 0, 1),
(3, 0, 1, 0),
(3, 0, 1, 1),
(3, 0, 2, 0),
(3, 0, 2, 1),
(3, 0, 3, 0),
(3, 0, 3, 1),
(3, 1, 0, 0),
(3, 1, 0, 1),
(3, 1, 1, 0),
(3, 1, 1, 1),
(3, 1, 2, 0),
(3, 1, 2, 1),
(3, 1, 3, 0),
(3, 1, 3, 1),
(4, 0, 0, 0),
(4, 0, 0, 1),
(4, 0, 1, 0),
(4, 0, 1, 1),
(4, 0, 2, 0),
(4, 0, 2, 1),
(4, 0, 3, 0),
(4, 0, 3, 1),
(4, 1, 0, 0),
(4, 1, 0, 1),
(4, 1, 1, 0),
(4, 1, 1, 1),
(4, 1, 2, 0),
(4, 1, 2, 1),
(4, 1, 3, 0),
(4, 1, 3, 1),
(5, 0, 0, 0),
(5, 0, 0, 1),
(5, 0, 1, 0),
(5, 0, 1, 1),
(5, 0, 2, 0),
(5, 0, 2, 1),
(5, 0, 3, 0),
(5, 0, 3, 1),
(5, 1, 0, 0),
(5, 1, 0, 1),
(5, 1, 1, 0),
(5, 1, 1, 1),
(5, 1, 2, 0),
(5, 1, 2, 1),
(5, 1, 3, 0),
(5, 1, 3, 1)]
which is really the output that I want. I just need to modify the code to accept divPair.values() in some way. So I write this:
from itertools import product
divPair = div_pair(84000)
list(product(range(i+1) for i in divPair.values()))
which seems to me as if it should be correct, but it outputs this mess:
[(range(0, 6),), (range(0, 2),), (range(0, 4),), (range(0, 2),)]
and I can't figure out how to fix it. There is a post here which offers fantastic solutions to what I am trying to do. I am just trying to work toward them with what I know.
product returns the product of its arguments, and you have passed it a single one, the (range(i+1) for i in divPair.values()) generator. The generator yielded a list of range objects. That's like doing this:
>>> list(product(['range', 'range', 'range']))
[('range',), ('range',), ('range',)]
You have to pass your ranges as individual arguments.
Do this:
list(product(*[range(i+1) for i in divPair.values()]))
(or this)
list(product(*(range(i+1) for i in divPair.values())))

Categories

Resources