Python Itertools Permutations - python

I am currently writing a program that uses itertools, and one piece of it does not seems to functioning properly. I would like the input that determines the length of the lists the permutation function outputs to be equal to length of the list from which it generates its outputs. In other words, I have
import itertools
b = 0
c = 9
d = [0,1,2]
e = len(d)
while b < c:
d.append(b)
b = b+1
print([x for x in itertools.permutations(d,e)])
And I would like this to generate all the possible permutations of d that are equal to this length. I have been experimenting with this and it seems that second determiner must be an integer. I even tried making a new variable, f, and having f = int(e) and then replacing e with f in the print statement, but with no success. With either of these all I got was [()]
Thanks for your help.

You need to set e after you build the list. len(d) returns a value, not a reference to the list's length.
d = range(0,9) # build an arbitrary list here
# this creates a list of numbers: [0,1,2,3,4,5,6,7,8]
e = len(d)
print list(itertools.permutations(d, e))
Note that the number of permutations is very large, so storing all of them in a list will consume large amounts of memory - you'd be better off with this:
d = range(0,9)
e = len(d)
for p in itertools.permutations(d, e):
print p

Related

Make Python code faster

Is it possible to make this code run faster?
a,b=map(int,input().split())
c=list(map(int,input().split()))
d=list(map(int,input().split()))
e=list(map(int,input().split()))
happy=0
for i in c:
if i in d:
happy=happy+1
elif i in e:
happy=happy-1
print(happy)
The code has to increment or decrement happy variable depending on if elements of c list are present in d or e lists. This code runs fine for small number of elements in c, d and e lists. But when there are many elements , the code execution is terminated due to timeout.
What can I do to make it run faster?
You can avoid the loop.
The variable happy is essentially the difference between the number of elements found in d and the number of elements found in e.
Could there be duplicates in c?
If you want to count the same element only once, then you can use set, that implicitly remove duplicates:
set_c = set(c)
happy_match = set_c.intersect(d)
unhappy_match = set_c.intersect(e)
happy = len(happy) - len(unhappy_match)
If you want to count each occurrence (including duplicates), then you can apply the same logic to lists:
happy_match = sum(1 if el in d else 0 for el in c)
unhappy_match = sum(1 if el in e else 0 for el in c)
happy = len(happy) - len(unhappy_match)

How to check if sum of 3 integers in list matches another integer? (python)

Here's my issue:
I have a large integer (anywhere between 0 and 2^32-1). Let's call this number X.
I also have a list of integers, unsorted currently. They are all unique numbers, greater than 0 and less than X. Assume that there is a large amount of items in this list, let's say over 100,000 items.
I need to find up to 3 numbers in this list (let's call them A, B and C) that add up to X.
A, B and C all need to be inside of the list, and they can be repeated (for example, if X is 4, I can have A=1, B=1 and C=2 even though 1 would only appear once in the list).
There can be multiple solutions for A, B and C but I just need to find one possible solution for each the quickest way possible.
I've tried creating a for loop structure like this:
For A in itemlist:
For B in itemlist:
For C in itemlist:
if A + B + C == X:
exit("Done")
But since my list of integers contains over 100,000 items, this uses too much memory and would take far too long.
Is there any way to find a solution for A, B and C without using an insane amount of memory or taking an insane amount of time? Thanks in advance.
you can reduce the running time from n^3 to n^2 by using set something like that
s = set(itemlist)
for A in itemlist:
for B in itemlist:
if X-(A+B) in s:
print A,B,X-(A+B)
break
you can also sort the list and use binary search if you want to save memory
import itertools
nums = collections.Counter(itemlist)
target = t # the target sum
for i in range(len(itemlist)):
if itemlist[i] > target: continue
for j in range(i+1, len(itemlist)):
if itemlist[i]+itemlist[j] > target: continue
if target - (itemlist[i]+itemlist[j]) in nums - collections.Counter([itemlist[i], itemlist[j]]):
print("Found", itemlist[i], itemlist[j], target - (itemlist[i]+itemlist[j]))
Borrowing from #inspectorG4dget's code, this has two modifications:
If C < B then we can short-circuit the loop.
Use bisect_left() instead of collections.Counter().
This seems to run more quickly.
from random import randint
from bisect import bisect_left
X = randint(0, 2**32 - 1)
itemset = set(randint(0,X) for _ in range(100000))
itemlist = sorted(list(itemset)) # sort the list for binary search
l = len(itemlist)
for i,A in enumerate(itemlist):
for j in range(i+1, l): # use numbers above A
B = itemlist[j]
C = X - A - B # calculate C
if C <= B: continue
# see https://docs.python.org/2/library/bisect.html#searching-sorted-lists
i = bisect_left(itemlist, C)
if i != l and itemlist[i] == C:
print("Found", A, B, C)
To reduce the number of comparisons, we enforce A < B < C.

Using recursion to create a list combination

I'm in trouble creating a combination of elements from list.
What i would like to do is to create a recursive function in Python which returns a combination of elements for example list a = [1,2,3,4,5,6,7,8] and a result will be combinations [1,2,3,4],[1,3,4,5],[1,4,5,6],[1,2,4,5] etc. For 8 elements it should return 70 combinations (if i did my math right). Although the best option would be that the combinations don't repeat.
I tried to code it, but what i get is only [1,2,3,4],[1,3,4,5] etc but not combination [1,5,7,8]
I know there is a special function but i'd like to do it recursively. Any suggestions?
nimed = ["A","B","C","D","E","F","G","H"]
def kombinatsioonid(listike,popitav):
if len(listike) < 4:
return
tyhi = []
for c in range(len(listike)):
tyhi.append(listike[c])
listike.pop(popitav)
print(tyhi)
kombinatsioonid(listike,popitav)
kombinatsioonid(nimed,1)
This can be done in this way :
def combination(l,n, mylist=[]):
if not n: print(mylist)
for i in range(len(l)):
mylist.append(l[i])
combination(l[i+1:], n-1, mylist)
mylist.pop()
l = ["A","B","C","D","E","F","G","H"]
n=4
combination(l, n)
For each element x in a, generate all k-1 combinations from the elements right to it, and prepend x to each one. If k==0, simply return one empty combination, thus exiting the recursion:
def combs(a, k):
if k == 0:
return [[]]
r = []
for i, x in enumerate(a):
for c in combs(a[i+1:], k - 1):
r.append([x] + c)
#print '\t' * k, k, 'of', a, '=', r
return r
Uncomment the "print" line to see what's going on.
As a side note, it's better to use English variable and function names, just for the sake of interoperability (your very question being an example).

Removing common elements in two lists

I have two sorted lists of positive integers which can have repeated elements and I must remove matching pairs of numbers, one from each list:
a=[1,2,2,2,3]
b=[2,3,4,5,5]
should become:
a=[1,2,2]
b=[4,5,5]
That is, the 2's and the 3's have been removed because they appear in both lists.
Set intersection can't be used here because of the repeated elements.
How do I go about this?
To remove elements appearing in both lists, use the following:
for i in a[:]:
if i in b:
a.remove(i)
b.remove(i)
To create a function which does it for you, simply do:
def removeCommonElements(a, b):
for e in a[:]:
if e in b:
a.remove(e)
b.remove(e)
Or to return new lists and not to edit the old ones:
def getWithoutCommonElements(a, b): # Name subject to change
a2 = a.copy()
b2 = b.copy()
for e in a:
if e not in b:
a2.remove(e)
b2.remove(e)
return a2, b2
However the former could be replaced with removeCommonElements like so:
a2, b2 = a.copy(), b.copy()
removeCommonElements(a2, b2)
Which would keep a and b, but create a duplicates without common elements.
The Counter object from collections can do this quite concisely:
from collections import Counter
a=Counter([1,2,2,2,3])
b=Counter([2,3,4,5,5])
print list((a-b).elements())
print list((b-a).elements())
The idea is:
Count up how often each element appears (e.g. 2 appears 3 times in a, and 1 time in b)
Subtract the counts to work out how many extra times the element appears (e.g. 2 appears 3-1=2 times more in a than b)
Output each element the extra number of times it appears (the collections elements method automatically drops any elements with counts less than 1)
(Warning: the output lists won't necessarily be sorted)
Given that the lists are sorted, you can merge/distribute element-wise, like for example:
x, y = [], []
while a and b:
if a[0] < b[0]:
x.append(a.pop(0))
elif a[0] > b[0]:
y.append(b.pop(0))
else: # a[0]==b[0]
a.pop(0)
b.pop(0)
x += a
y += b
The solution given by #Mahi is nearly correct. The simplest way to achieve what you want is this:
def remove_common_elements(a, b):
for i in a[:]:
if i in b:
a.remove(i)
b.remove(i)
return a, b
The important thing here is to make a copy of a by writing a[:]. If you iterate through a list while removing elements from it, you won't get correct results.
If you don't want to modify the lists in place, make a copy of both lists beforehand and return the copied lists.
def remove_common_elements(a, b):
a_new = a[:]
b_new = b[:]
for i in a:
if i in b_new:
a_new.remove(i)
b_new.remove(i)
return a_new, b_new
One solution would be to create a new copy of a and removing common elements from b.
a = [1,2,2,2,3]
b = [2,2,3,4,5]
a_new = []
for ai in a:
if ai in b:
b.remove(ai)
else:
a_new.append(ai)
print a_new
print b

Shuffling a list

in this program I'm trying to shuffle a list by randomly choosing two items from a list and swapping them round, and then repeating this process several times.
The problem I have encountered is I don't know how I can swap the items round and print the shuffled list.
For instance if my two random values were a and b, if I were to just put:
a = b
b = a
then that would change the value of a to b, but when it tries to change b to a, no change would occur as a has already been changed to b.
The only way I can think that this would work is swapping them at the same time, but I do not know of a function/ way to swap them round.
Also if a, b were items of a list L, after I swapped them round if I used
print L
should it print the altered version? I only ask because from what I have tried it is not doing that.
NB I am trying to shuffle this list stage by stage by swapping, instead of using the shuffle function imported from random.
In Python, you can swap two variables like this:
a, b = b, a
This is called multiple assignment, you can find more information about it here.
In other languages this is usually done by assigning a temporary variable:
tmp = a
a = b
b = tmp
Isn't Python great?
The random.shuffle function uses swapping too. It would be worthwhile to look at its source code:
def shuffle(self, x, random=None, int=int):
"""x, random=random.random -> shuffle list x in place; return None.
Optional arg random is a 0-argument function returning a random
float in [0.0, 1.0); by default, the standard random.random.
"""
if random is None:
random = self.random
for i in reversed(xrange(1, len(x))):
# pick an element in x[:i+1] with which to exchange x[i]
j = int(random() * (i+1))
x[i], x[j] = x[j], x[i]
Observe how the last line performs a swap using tuple packing and unpacking.
As an alternative to packing and unpacking, the traditional way to swap variables is to use a temporary variable:
t = x[i]
x[i] = x[j]
x[j] = t
Use a temp variable for your first problem:
temp = a
a = b
b = temp
In Python you can also do this:
a, b = b, a
I suspect your second problem is because you're changing things you got out of the list, instead of changing the list. Try this:
i, j = # two indexes to swap in the list
L[i], L[j] = L[j], L[i]
Use a temporary variable:
temp = a
a = b
b = temp
http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
Just swapping items is known to be bad.
Don't forget that if you have n items, there are n! arrangements. If your random number is 32 bits, there are 2^32 numbers.
It's hard then to shuffle a pack of cards with a 32 bit number as 52! is very much bigger than 2^32

Categories

Resources