I dont know how to properly ask this question but here is what I am trying to do.
lists = []
for x in range(3):
for y in range(3):
if x!=y:
lists.append([x,y])
Is there a simple solution so it doesnt give me lists that are the same but reversed:
for example [2,0] and [0,2]?
I know I could go through the lists and remove them afterwards but is there a solution to not even make the list? (sorry my english isnt perfect)
You can use itertools.combinations
>>> from itertools import combinations
>>> list(combinations(range(3), 2))
[(0, 1), (0, 2), (1, 2)]
With the above example we take any combination of two elements from range(3) without repeating any elements.
Sure: if you add all pairs with y > x instead of all possible pairs, only one of each pair (x, y) and (y, x) will appear.
lists = []
for x in range(3):
for y in range(x + 1, 3):
lists.append([x,y])
If you don't want those "duplicates", you want a combination
a combination is a way of selecting items from a collection, such that (unlike permutations) the order of selection does not matter
>>> import itertools
>>> list(itertools.combinations(iterable=range(3), r=2))
[(0, 1), (0, 2), (1, 2)]
Above I have used combinations() from the Python module itertools.
Explanation
I've set r=2 because you want a subsequence length of 2 (the form you described as [x, y])
The iterable=range(3) parameter is just a list of elements that are going to be used to make combinations of, so range(3) would result in [0, 1, 2]
The list() applied to the end result is simply to force the output to be printed out to the console because otherwise itertools.combinations returns an iterable that you iterate through to pull the elements one by one.
Easy:
for x in range(3):
for y in range(x, 3):
lists.append([x,y])
Related
I'm trying to solve the problem from the Rosalind.
Return: The total number of signed permutations of length n, followed by a list of
all such permutations (you may list the signed permutations in any order).
I have an idea for a solution in Python, but I cannot implement it to the end. Consider for example that n = 2.
numbers = [1, -1, 2, -2]
ordering = permutations(numbers,n)
So now I've got some tuples as a result:
(1, -1) (1, 2) (1, -2) (-1, 1) (-1, 2) (-1, -2) (2, 1) (2, -1) (2, -2) (-2, 1)
(-2, -1) (-2, 2)
I need to exclude those that have elements of equal modulus. For example, (-1, 1). Is it possible to implement this, and if possible, how?
A pythonic solution using list comprehension:
filtered_perms = [(x,y) for x,y in ordering if abs(x) != abs(y)]
Edit:
Code that works fine with python 3.7:
import itertools as itt
# create permutation generator object
perms = itt.permutations([-2, -1, 1, 2], 2)
# here generator is turned into a list with certain permutations excluded
filtered_perms = [(x,y) for x,y in perms if abs(x) != abs(y)]
# print whole list
print(filtered_perms)
# print first permutation
print(filtered_perms[0])
# print length of the list
print(len(filtered_perms))
Edit2:
To fix the problem with no elements in ordering:
ordering = list(itertools.permutations([-2, -1, 1, 2],2))
after that, ordering will be a list of all elements from itertools.permutations.
The solutions proposed before are right, but if in the case that you want to process the resulting list after generating the permutations would be a nice idea to have a generator instead of a list. For that, I recommend you to design your own generator function based on itertools.permutations:
def signed_permutations(iterable, r=2):
for item in permutations(iterable, r):
if abs(item[0]) != abs(item[1]):
yield item
And you can use it as:
for item in signed_permutations(numbers):
do_something(item)
Or if you just want to create a list:
sigperm = list(signed_permutations(numbers))
The filter function is probably what you're looking for.
list(filter(lambda pair: abs(pair[0]) != abs(pair[1]), ordering))
The condition might be wrong, I'm not sure what you mean by equal modulus.
I would like to loop through a list checking each item against the one following it.
Is there a way I can loop through all but the last item using for x in y? I would prefer to do it without using indexes if I can.
Note
freespace answered my actual question, which is why I accepted the answer, but SilentGhost answered the question I should have asked.
Apologies for the confusion.
for x in y[:-1]
If y is a generator, then the above will not work.
the easiest way to compare the sequence item with the following:
for i, j in zip(a, a[1:]):
# compare i (the current) to j (the following)
If you want to get all the elements in the sequence pair wise, use this approach (the pairwise function is from the examples in the itertools module).
from itertools import tee, izip, chain
def pairwise(seq):
a,b = tee(seq)
b.next()
return izip(a,b)
for current_item, next_item in pairwise(y):
if compare(current_item, next_item):
# do what you have to do
If you need to compare the last value to some special value, chain that value to the end
for current, next_item in pairwise(chain(y, [None])):
if you meant comparing nth item with n+1 th item in the list you could also do with
>>> for i in range(len(list[:-1])):
... print list[i]>list[i+1]
note there is no hard coding going on there. This should be ok unless you feel otherwise.
To compare each item with the next one in an iterator without instantiating a list:
import itertools
it = (x for x in range(10))
data1, data2 = itertools.tee(it)
data2.next()
for a, b in itertools.izip(data1, data2):
print a, b
This answers what the OP should have asked, i.e. traverse a list comparing consecutive elements (excellent SilentGhost answer), yet generalized for any group (n-gram): 2, 3, ... n:
zip(*(l[start:] for start in range(0, n)))
Examples:
l = range(0, 4) # [0, 1, 2, 3]
list(zip(*(l[start:] for start in range(0, 2)))) # == [(0, 1), (1, 2), (2, 3)]
list(zip(*(l[start:] for start in range(0, 3)))) # == [(0, 1, 2), (1, 2, 3)]
list(zip(*(l[start:] for start in range(0, 4)))) # == [(0, 1, 2, 3)]
list(zip(*(l[start:] for start in range(0, 5)))) # == []
Explanations:
l[start:] generates a a list/generator starting from index start
*list or *generator: passes all elements to the enclosing function zip as if it was written zip(elem1, elem2, ...)
Note:
AFAIK, this code is as lazy as it can be. Not tested.
Can anyone help me one this one?
I am trying to find a way to count the range between 2 list on integers; and to get each step necessary to get from one list to then next
using these 2 arrays:
a = [1,1,1]
b = [3,4,3]
I'd like to arrive to a sequence of in-between values:
[[2,2,2], [None,3,None]]
Thanks
a
This is quite simple to do with itertools.zip_longest() and a list comprehension:
>>> import itertools
>>> list(itertools.zip_longest(*[range(i+1, j) for i, j in zip(a, b)]))
[(2, 2, 2), (None, 3, None)]
Note that in 2.x itertools.zip_longest() doesn't exist - it's called itertools.izip_longest() instead.
This works by zip()ing the values together so we get the bounds, then we generate the range we need (adding one to the lower bound as you seem to not want to include it), then we separate them out into parts, using itertools.zip_longest() (which also introduces the None values).
A variation of Lattywares Answer that works in python 2.5 and below where izip_longest is not available:
map(None, *[range(x + 1, y) for x, y in zip(a, b)])
Lets say I have the following list:
lst = [0,1,3,a,b,c]
I would like the final outcome to be all possible permutations of lst, but be 20 characters long.
I have looked and can only find examples that would create a final outcome that would be 6 or less in length.
Any ideas?
I think itertools.product is what you're looking for.
# A simple example
import itertools
lst = [0, 1]
print(list(itertools.product(lst, repeat=2)))
# [(0, 0), (0, 1), (1, 0), (1, 1)]
Note that itertools.product itself returns an itertools.product object, not a list.
# In your case
import itertools
lst = [0, 1, 3, a, b, c]
output = list(itertools.product(lst, repeat=20))
Are you sure you want all permutations? Assuming you want to reuse characters (not a permutation) that would be a list with a length of 6^20.
If you want one string of length 20 built from characters in that list, this should do the job:
from random import choice
''.join(choice(chars) for _ in range(length))
The problem is that permutations and combinations (if you use itertools) follow the definition that each result can only physically exist if it is of equal or lesser length than the originating list.
If you are suggesting that you want one of the valid results to be "013abc013abc013abc01", then you'll have to modify your list to just be 20 items long and be made up of those 6 values.
from itertools import permutations
i = [0,1,3,'a','b','c',0,1,3,'a','b','c',0,1,3,'a','b','c',0,1]
results = []
for a in permutations(i, 20):
results.append(a)
list(permutations(lst,x)) ; where lst is iterable (your input list) and x is the no of elements
for example:
In [8]: lst = [0, 1, 3, 'a', 'b', 'c']
In [9]: from itertools import permutations
In [10]: result=[list(permutations(lst,x)) for x in range(1,len(lst))]
Up to this point in time, in Python, I've only ever seen list comprehensions that specify the inclusion of one element at time. For example, they're all in the following form
[f(x) for x in <iterable>]
Is there any way to specify more than one element at a time? For example,
[f(x), g(x) for x in <iterable>]
I'm asking because I want to create a list comprehension that calculates all the divisors of some number x, but I want to do this as efficiently as possible. Right now I'm using the following,
[y for y in range(1,x+1) if x%y == 0]
but I'd like to do something like this,
[y, x/y for y in range(1, sqrt(x)+1) if x%y == 0]
as this would be more efficient. Btw, I have no practical reason for doing this. It's simply a challenge problem that somebody told me and the goal is to do it with the smallest, most efficient list comprehension possible.
Thanks in advance.
Edit: Ok, it looks like I have to use tuples. I was trying to avoid that though as I'd then have to make another function to flatten the list which would make my solution longer.
Edit 2: Just in case anyone stumbles upon this question, the answer to what I wanted to do in my original question is this:
[y for x in <iterable> for y in f(x), g(x)]
It uses nested for loops in the list comprehension to get the job done.
You can flatten it in place
[y if i else x/y for y in range(1, sqrt(x)+1) for i in 0,1 if x%y == 0]
You can assign to tuples
[(y, x/y) for y in range(1, int(sqrt(x))+1) if x%y == 0]
Not really related to your basic question, but your example: I had to convert the 2nd parameter of range() to an int since sqrt() resulted in a float in my test code.
Update re Edit in post:
To flatten this list of tuples:
In [24]: s
Out[24]: [(1, 20), (2, 10), (4, 5)]
use this:
In [25]: import operator
create a tuple:
In [26]: reduce(operator.add, s, ())
Out[26]: (1, 20, 2, 10, 4, 5)
create a list:
In [27]: list(reduce(operator.add, s, ()))
Out[27]: [1, 20, 2, 10, 4, 5]
Note: In a helpful comment #jamylak points out that reduce and operator.add run order O(N^2), and that using itertools.chain would be much more efficient. This becomes more important as the size of the list grows and should be considered in that case.
Yes, you can do it. You just need to put parentheses around the element. What you get is a list of tuples.
>>> [(x, x+1) for x in range(5)]
[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]
Oh so close:
[(y, x/y) for y in range(1, sqrt(x)+1) if x%y == 0]
It is possible to generate a list of tuples, and these of course can hold multiple values.
Yes absolutely, just use parenthesis around the value:
[(y, x/y) for y in range(1, sqrt(x)+1) if x%y == 0]