Setting a range as an argument in itertools.permutations [duplicate] - python

This question already has answers here:
Powersets in Python using itertools
(3 answers)
Closed 3 years ago.
I want to print all permutations of length 1-4 for the following list [1,2,3,4]
I know I could just set up a for-loop and pass in the for-loop index as an argument, but I was trying to get the following code to work:
import itertools
nums = [1,2,3,4]
perms = itertools.permutations(nums,range(1,4))
print(list(perms))
The hope was that the argument range(1,4) would run the intertools.permutations(nums) on string lengths 1, 2, 3 and 4.
Any ideas if it is possible to do this using the itertools notation?
Would it also be possible to print the case for length = 1 as:
(1), (2), (3), (4)
not
(1,), (2,), (3,), (4,)

Chain together 4 calls of permutations:
from itertools import chain, permutations
nums = [1,2,3,4]
perms = list(chain.from_iterable(permutations(nums, i) for i in range(1,5)))
print(perms)
If you want to print the 1-tuples as individual values, you'll need to handle that separately:
for t in perms:
if len(t) == 1:
print("(t[0])")
else:
print(t)
That's if you are concerned about the appearance of the tuple. If you truly want a non-tuple value, you'll need to extract the value separately, and keep in mind that 1 and (1) are the exact same value.
perms = list(nums, # permutations(nums, 1) == nums
chain.from_iterable(permutations(nums, i) for i in range(2,5)))

You can also write it as a generator expression:
perms = (it for i in range(1, 4) for it in itertools.permutations(nums,i))

Related

Subtraction of within a list [duplicate]

This question already has answers here:
Compare two adjacent elements in same list
(2 answers)
Multiply Adjacent Elements
(5 answers)
Rolling or sliding window iterator?
(29 answers)
Closed 1 year ago.
i'm using Python and I have the following list A = [10,20,30,40]
how can obtain a new list such as I'm adding the second element to the first, the third to the second and fourth to the third. Meaning the output would be [30,50,70].
Can use simple list comprehension like this:
a = [10,20,30,40]
b = [a[i] + a[i+1] for i in range(len(a)-1)]
b
[30, 50, 70]
Take a look at the pairwise recipe from the itertools module (which will be added as a function of itertools in 3.10). Once you've copied that, you can just do:
[x + y for x, y in pairwise(A)]
or for fun with less custom code, add imports from operator import add and from itertools import starmap and you can make an iterator that produces the results lazily with:
starmap(add, pairwise(A)) # Wrap in list if you need a list
a = [10,20,30,40,50]
new_list = []
for i in range(1, len(a)):
new_list.append(a[i] + a[i-1])
When we do range(1, len(a)), we create a set of indexes which are [1,2,3,4].
So when we do:
for i in range(1, len(a)): it's kind of like doing for i in range [1,2,3,4].
If we now imagine we are doing:
for i in [1,2,3,4]:
new_list.append(a[i] + a[i-1])
What it's doing is getting the current value of a at i and adding it a at the previous index i-1 and appending the result to a new list.

Why does my string.split in Python return unwanted values? [duplicate]

This question already has answers here:
How to get the n next values of a generator into a list
(5 answers)
Fetch first 10 results from a list in Python
(4 answers)
Closed 13 days ago.
With linq I would
var top5 = array.Take(5);
How to do this with Python?
Slicing a list
top5 = array[:5]
To slice a list, there's a simple syntax: array[start:stop:step]
You can omit any parameter. These are all valid: array[start:], array[:stop], array[::step]
Slicing a generator
import itertools
top5 = itertools.islice(my_list, 5) # grab the first five elements
You can't slice a generator directly in Python. itertools.islice() will wrap an object in a new slicing generator using the syntax itertools.islice(generator, start, stop, step)
Remember, slicing a generator will exhaust it partially. If you want to keep the entire generator intact, perhaps turn it into a tuple or list first, like: result = tuple(generator)
import itertools
top5 = itertools.islice(array, 5)
#Shaikovsky's answer is excellent, but I wanted to clarify a couple of points.
[next(generator) for _ in range(n)]
This is the most simple approach, but throws StopIteration if the generator is prematurely exhausted.
On the other hand, the following approaches return up to n items which is preferable in many circumstances:
List:
[x for _, x in zip(range(n), records)]
Generator:
(x for _, x in zip(range(n), records))
In my taste, it's also very concise to combine zip() with xrange(n) (or range(n) in Python3), which works nice on generators as well and seems to be more flexible for changes in general.
# Option #1: taking the first n elements as a list
[x for _, x in zip(xrange(n), generator)]
# Option #2, using 'next()' and taking care for 'StopIteration'
[next(generator) for _ in xrange(n)]
# Option #3: taking the first n elements as a new generator
(x for _, x in zip(xrange(n), generator))
# Option #4: yielding them by simply preparing a function
# (but take care for 'StopIteration')
def top_n(n, generator):
for _ in xrange(n):
yield next(generator)
The answer for how to do this can be found here
>>> generator = (i for i in xrange(10))
>>> list(next(generator) for _ in range(4))
[0, 1, 2, 3]
>>> list(next(generator) for _ in range(4))
[4, 5, 6, 7]
>>> list(next(generator) for _ in range(4))
[8, 9]
Notice that the last call asks for the next 4 when only 2 are remaining. The use of the list() instead of [] is what gets the comprehension to terminate on the StopIteration exception that is thrown by next().
Do you mean the first N items, or the N largest items?
If you want the first:
top5 = sequence[:5]
This also works for the largest N items, assuming that your sequence is sorted in descending order. (Your LINQ example seems to assume this as well.)
If you want the largest, and it isn't sorted, the most obvious solution is to sort it first:
l = list(sequence)
l.sort(reverse=True)
top5 = l[:5]
For a more performant solution, use a min-heap (thanks Thijs):
import heapq
top5 = heapq.nlargest(5, sequence)
With itertools you will obtain another generator object so in most of the cases you will need another step the take the first n elements. There are at least two simpler solutions (a little bit less efficient in terms of performance but very handy) to get the elements ready to use from a generator:
Using list comprehension:
first_n_elements = [generator.next() for i in range(n)]
Otherwise:
first_n_elements = list(generator)[:n]
Where n is the number of elements you want to take (e.g. n=5 for the first five elements).
This should work
top5 = array[:5]

Lists in the python

We have to accept a list and find the subsequent from the list such that number in subsequence are in increasing order.
Find sum of each subsequence
return maximum sum
For example
Input=[1, 4,2]
Possible subsequence will be [1][4][2][1,4][1,2]
Here [4,2] will not come as 4 is greater. And order should not change. Means first position elements if it comes in sublist it should be first
Sum of each subsequence will be 1,4,2,5,3
Output will be 5.
What will be your logic to solve it?
You can use itertools.combinations and itertools.chain to do this easily
>>> from itertools import combinations, chain
>>> Input=[1, 4,2]
>>> max(map(sum, (filter(lambda x: sorted(x) == list(x), chain(*[combinations(Input, i) for i in range(1, len(Input)+1)])))))
5
Explanation
>>> possibilities = chain(*[combinations(Input, i) for i in range(1, len(Input)+1)])
>>> filtered_possibilities = filter(lambda x: sorted(x) == list(x), possibilities)
>>> sum_of_each_possibility = map(sum, filtered_possibilities)
>>> max_sum = max(sum_of_each_possibility)
>>> print (max_sum)
5
You can break down the question into three steps:
1) Find the power_set(all sub lists) of list.
2) Filter out unwanted list (list with decreasing order).
3) Find the max sum.
Step1:
def powerset(s):
x = len(s)
res=[]
for i in range(1 << x):
res.append([s[j] for j in range(x) if (i & (1 << j))])
return res
lst=[1,4,2]
res=powerset(lst)
Step 2&3:
def max_sub(lsts):
max_out=0
def helper(lsts): #Step2: to filter out decreasing lists.
if lsts==[]:
return False
else:
for i in range(len(lsts)-1):
if lsts[i]>lsts[i+1]:
return False
return True
filtered_lst=list(filter(lambda x:helper(x),lsts))
for lst in filtered_lst:
max_out=max(max_out,sum(lst)) #step3: Find out the max sub list sum.
return max_out
print(max_sub(res))
Result:
5
Drako already mentioned, that this is not free coding service. Show some effort yourself and tell us, what you already tried and how it didn't work. also provide output to help us analyze the problem. I'll help anyway; also welcome to StackOverflow.
What you are looking for is a "power set". An exhaustive set M of sets s, where each s is a subset of M and there is in fact no subset of M which is not already contained in a s. As sets are unordered by definition, you don't have to care about duplicates because of different ordering. Looking at this question
There is a nice answer to get the power set of a given set. Assuming your input list/set/iterable is i, you can use the following code to get the power set list.
from itertools import chain, combinations
def get_power_set(i):
i.sort() # Sorted input --> sorted output
ps_iterable = chain.from_iterable(combinations(i, r) for r in range(len(i)+1))
return list(ps_iterable)
def get_highest_sum(input_list):
maximum = 0
for s in input_list:
sum_of_set = sum(s)
if sum_of_set > maximum:
maximum = sum_of_set
return maximum
i = [1,2,3] # Assign your input list here
power_set = get_power_set(i)
highest_sum = get_highest_sum(power_set)
print(power_set)
# >>> [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
print("Highest sum is {}".format(highest_sum))
# >>> 6

Python 3: pairwise iterating through list [duplicate]

This question already has answers here:
Iterating over every two elements in a list [duplicate]
(22 answers)
Closed 4 years ago.
I am looking for a nice pythonian solution to read two elements out of a list in Python 3. What do I need to write for ??? in the following code:
it = [1,2,3,4,5,6]
for x, y in ??? :
print (x, y)
The desired output would be:
1 2
3 4
5 6
Also one could solve it with indexed for-loop. But this is also ugly (IMHO)
Use zip(*[iter(it)] * 2), as seen in this answer.
it = [1,2,3,4,5,6]
for x, y in zip(*[iter(it)] * 2):
print(x, y)
Another easy way without zip is:
i = 0
while i < len(it)-1:
print(it[i], it[i+1])
i += 2
Another cheap option, using indices. You might not like them, but they are fast.
it = [1,2,3,4,5,6]
for x in range(0, len(it)-1, 2):
print(it[x], it[x+1])
Here is another approach which will work in Python3:
def pair(a):
# Or simply:
# return zip(a[::2], a[1::2])
for k, v in zip(a[::2], a[1::2]):
yield k, v
a = [1,2,3,4,5,6]
final = list(pair(a))
print(final)
Output:
[(1, 2), (3, 4), (5, 6)]
Got this to work for your case:
l = [1,2,3,4,5,6]
print(*[' '.join([str(a) for a in x]) for x in zip(l[::2],l[1:][::2])],sep='\n')
First I had to use l[::2] to create a list the odd numbers in the list, then l[1:][::2] to get even numbers. Did this using slicing function which is quite useful link
Then I zipped them together to match 1st, 2nd, 3rd elements etc link
Then I used list comprehension to create a list of each of those sets. The problem is that they were sets and not text as above. To resolve this I changed my sets to string str() .
Now that the individual sets have been turned into string, you can join with ' '.
You still have a set of 3 but you can print each line with print(*[list here],sep='\n') link
Learned a few new tricks, hope this helps!

How to take the first N items from a generator or list? [duplicate]

This question already has answers here:
How to get the n next values of a generator into a list
(5 answers)
Fetch first 10 results from a list in Python
(4 answers)
Closed 12 days ago.
With linq I would
var top5 = array.Take(5);
How to do this with Python?
Slicing a list
top5 = array[:5]
To slice a list, there's a simple syntax: array[start:stop:step]
You can omit any parameter. These are all valid: array[start:], array[:stop], array[::step]
Slicing a generator
import itertools
top5 = itertools.islice(my_list, 5) # grab the first five elements
You can't slice a generator directly in Python. itertools.islice() will wrap an object in a new slicing generator using the syntax itertools.islice(generator, start, stop, step)
Remember, slicing a generator will exhaust it partially. If you want to keep the entire generator intact, perhaps turn it into a tuple or list first, like: result = tuple(generator)
import itertools
top5 = itertools.islice(array, 5)
#Shaikovsky's answer is excellent, but I wanted to clarify a couple of points.
[next(generator) for _ in range(n)]
This is the most simple approach, but throws StopIteration if the generator is prematurely exhausted.
On the other hand, the following approaches return up to n items which is preferable in many circumstances:
List:
[x for _, x in zip(range(n), records)]
Generator:
(x for _, x in zip(range(n), records))
In my taste, it's also very concise to combine zip() with xrange(n) (or range(n) in Python3), which works nice on generators as well and seems to be more flexible for changes in general.
# Option #1: taking the first n elements as a list
[x for _, x in zip(xrange(n), generator)]
# Option #2, using 'next()' and taking care for 'StopIteration'
[next(generator) for _ in xrange(n)]
# Option #3: taking the first n elements as a new generator
(x for _, x in zip(xrange(n), generator))
# Option #4: yielding them by simply preparing a function
# (but take care for 'StopIteration')
def top_n(n, generator):
for _ in xrange(n):
yield next(generator)
The answer for how to do this can be found here
>>> generator = (i for i in xrange(10))
>>> list(next(generator) for _ in range(4))
[0, 1, 2, 3]
>>> list(next(generator) for _ in range(4))
[4, 5, 6, 7]
>>> list(next(generator) for _ in range(4))
[8, 9]
Notice that the last call asks for the next 4 when only 2 are remaining. The use of the list() instead of [] is what gets the comprehension to terminate on the StopIteration exception that is thrown by next().
Do you mean the first N items, or the N largest items?
If you want the first:
top5 = sequence[:5]
This also works for the largest N items, assuming that your sequence is sorted in descending order. (Your LINQ example seems to assume this as well.)
If you want the largest, and it isn't sorted, the most obvious solution is to sort it first:
l = list(sequence)
l.sort(reverse=True)
top5 = l[:5]
For a more performant solution, use a min-heap (thanks Thijs):
import heapq
top5 = heapq.nlargest(5, sequence)
With itertools you will obtain another generator object so in most of the cases you will need another step the take the first n elements. There are at least two simpler solutions (a little bit less efficient in terms of performance but very handy) to get the elements ready to use from a generator:
Using list comprehension:
first_n_elements = [generator.next() for i in range(n)]
Otherwise:
first_n_elements = list(generator)[:n]
Where n is the number of elements you want to take (e.g. n=5 for the first five elements).
This should work
top5 = array[:5]

Categories