Combinations using Recursion [duplicate] - python

I have the following python function to print all subsets of a list of numbers:
def subs(l):
if len(l) == 1:
return [l]
res = []
for sub in subs(l[0:-1]):
res.append(sub)
res.append([l[-1]])
res.append(sub+[l[-1]])
return res
li = [2, 3, 5, 8]
print(subs(li))
This returns:
[[2], [8], [2, 8], [5], [8], [5, 8], [2, 5], [8], [2, 5, 8], [3], [8], [3, 8], [5], [8], [5, 8], [3, 5], [8], [3, 5, 8], [2, 3], [8], [2, 3, 8], [5], [8], [5, 8], [2, 3, 5], [8], [2, 3, 5, 8]]
Which is not the expected answer. It looks like python takes the list l into the function by reference. So when I append l[-1], it appends the last element of original list, not the smaller list sent into the recursive method. Is there any way to solve this?
This could possibly be solved using tuples but I'm wondering if there is a solution using lists.

def subs(l):
if l == []:
return [[]]
x = subs(l[1:])
return x + [[l[0]] + y for y in x]
Results:
>>> print (subs([1, 2, 3]))
[[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]]

There is a convenient Python module to help:
import itertools
def subs(l):
res = []
for i in range(1, len(l) + 1):
for combo in itertools.combinations(l, i):
res.append(list(combo))
return res
The results are:
>>> subs([1,2,3])
[[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

Actually there is no problem with Python call by reference as I originally thought. In that case l[-1] would be 8 in all recursive calls. But l[-1] is 3, 5, 8 respectively in the recursive calls. This modified function solves the issue:
def subs(l):
if len(l) == 1:
return [l]
res = []
subsets = subs(l[0:-1])
res = res+subsets
res.append([l[-1]])
for sub in subsets:
res.append(sub+[l[-1]])
return res
returns:
[[2], [3], [2, 3], [5], [2, 5], [3, 5], [2, 3, 5], [8], [2, 8], [3, 8], [2, 3, 8], [5, 8], [2, 5, 8], [3, 5, 8], [2, 3, 5, 8]]

Improving on #Miguel Matos answer
def subsets(set_inp):
if set_inp == []:
return [[]]
x = subsets(set_inp[1:])
return sorted( x + [[set_inp[0]] + y for y in x])
print(subsets([1,2,3]))

using #Miguel Matos idea
we can get these in lexicographical order by,
def foo(l, p = [], d = {}):
if len(l)==0:
return [[]]
x = foo(l[:-1])
return x+ [[l[-1]] + y for y in x]
returns
[[], [1], [2], [2, 1], [3], [3, 1], [3, 2], [3, 2, 1], [4], [4, 1], [4, 2], [4, 2, 1], [4, 3], [4, 3, 1], [4, 3, 2], [4, 3, 2, 1]]

You can avoid using comprehensions or for-loops by using lambda functions and map.
I consider this a proper 'functional' powerset function in Python:
def powerSet(input):
# at tree leaf, return leaf
if len(input)==0:
return [[]];
# if not at a leaf, trim and recurse
# recursion is illustrated as follows:
# e.g. S = {1,2,3}
# S_trim = S without first element:
# {(),(2),(3),(2,3)}
# S_trim concatenated with first element:
# {(1),(1,2),(1,3),(1,2,3)}
# we keep the character sliced from front and concat it
# with result of recursion
# use map to apply concatenation to all output from powerset
leading = (input[0])
new_input = input[1:len(input)]
ps1 = list((powerSet(new_input)))
# concatenate over powerset-ed set
ps2 = map(lambda x: [leading]+x,ps1)
ps_list = list(map(lambda x: list(x),ps2))
return ps1+ ps_list

Continuing on the answers provided by #Miguel and #Abdul...the following function insures a lexicographically ordered output.
def subset(A):
if A == []:
return [[]]
sub = subset(A[:-1])
return sub + [rem + [A[-1]] for rem in sub]
tests = [[], [1], [1,2], [1,2,3]]
for test in tests:
print(subset(test))
RESULT
[[]]
[[], [1]]
[[], [1], [2], [1, 2]]
[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]

Related

How to iterate two lists with different length together? [duplicate]

This question already has answers here:
Is there a zip-like function that pads to longest length?
(8 answers)
Closed 1 year ago.
I got two lists as shown below:
a = [[[1,2], [3, 4], [5,6]], [[8,9],[10,11]]]
b = [[[1,2], [1,3],[2,3],[3, 4],[4,6],[5,6]],[[8,9],[9,10],[10,11]]]
The values in both lists are a group of list of coordinate points. And you can notice that some of the coordinate points in list a are also shown in list b
My goal is to slice list b from the given coordinate points from list a and then append in a new list. Here is an example of what I expect to get.
Example
The first item of list a is [[1,2], [3, 4], [5,6]] which I named as a[0] while that of list b is [[1,2], [1,3],[2,3],[3, 4],[4,6],[5,6]] which I named as b[0]. Therefore, a[0] is a set of b[0]
I want to slice b[0] based on the values in a[0] into a new list which looks like [[[1,2],[1,3],[2,3],[3,4]],[[3, 4],[4,6],[5,6]]]. In other words, a[0] serves as the slicing index of b[0].
Below is my code, and I do not have any idea to execute the above statement.
for items in a:
c.append([])
for i,j in zip(range(len(items)),range(len(b))):
if i < len(items)-1:
L_i = b[j][b[j].index(a[i]):b[j].index(a[i+1])+1]
L_i = list(tuple(item) for item in L_i)
elif i == len(concave_points)-1:
temp1 = b[j][b[j].index(a[i]):]
temp2 =b[j][0:b[j].index(a[0])+1]
L_i = temp1 + temp2
L_i = list(tuple(item) for item in L_i)
And an error ValueError: [[1, 2], [3, 4], [5, 6]] is not in list is occured.
Thanks a lot.
You can zip the lists instead of their length and just slice the sublists by index
a = [[[1, 2], [3, 4], [5, 6]], [[8, 9], [10, 11]]]
b = [[[1, 2], [1, 3], [2, 3], [3, 4], [4, 6], [5, 6]], [[8, 9], [9, 10], [10, 11]]]
c = []
for aa, bb in zip(a, b):
for i in range(len(aa) - 1):
c.append(bb[bb.index(aa[i]):bb.index(aa[i + 1]) + 1])
print(c) # [[[1, 2], [1, 3], [2, 3], [3, 4]], [[3, 4], [4, 6], [5, 6]], [[8, 9], [9, 10], [10, 11]]]
And as on liner with list comprehensions
c = [bb[bb.index(aa[i]):bb.index(aa[i + 1]) + 1] for aa, bb in zip(a, b) for i in range(len(aa) - 1)]
a = [[1, 2], [3, 4], [5, 6]]
b = [[1, 2], [1, 3], [2, 3], [3, 4], [4, 6], [5, 6]]
union_a_b = []
a.extend(b)
for pair in a:
if pair not in union_a_b:
union_a_b.append(pair)
else:
continue
print(union_a_b)

Join list of lists into a delimiter separated list of lists

I have the following list of lists and a delimiter:
lsts = [[1, 2, 3], [4, 5], [6]]
delim = ['delim']
I'd like to mimic the string.join() behavior.
expected output is:
lst = [[1, 2, 3], ['delim'], [4, 5], ['delim'], [6]]
I tried:
from itertools import chain
n = 2
ele = 'x'
lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list(chain(*[lst[i:i+n] + [ele] if len(lst[i:i+n]) == n else lst[i:i+n] for i in xrange(0, len(lst), n)]))
# which flattens the list and then inserst elements every second position,
# which doesn't help if the lists inside the list are of different length.
Try this:
lsts = [[1, 2, 3], [4, 5], [6]]
delim = ['delim']
place_holder = []
for i in lsts:
place_holder.append(i)
place_holder.append(delim)
place_holder.pop() # Pop the last element :)
print(place_holder)
You can use slice assignment
def list_join(seq, delim):
res = [delim]*(len(seq) * 2 - 1)
res[::2] = seq
return res
delim = ['delim']
# empty list
lsts = [[]]
print(list_join(lsts, delim))
# even length
lsts = [[1, 2, 3], [4, 5], [6], [7]]
print(list_join(lsts, delim))
# odd length
lsts = [[1, 2, 3], [4, 5], [6]]
print(list_join(lsts, delim))
Output
[[]]
[[1, 2, 3], ['delim'], [4, 5], ['delim'], [6], ['delim'], [7]]
[[1, 2, 3], ['delim'], [4, 5], ['delim'], [6]]
Here is my solution. It looks like the shortest code.
for i in range(len(lsts) - 1, 0, -1):
lsts.insert(i, delim)
print(lsts)
This uses a simple for loop that validates the position on the item isn’t the last item before adding the delimiter.
lsts = [[1, 2, 3], [4, 5], [6]]
delim = ['delim']
output = []
for i, l in enumerate(lsts):
output.append(l)
if i < (len(lsts) - 1):
output.append(delim)
After trying to solve it for quite a while and reviewing the other answers, I came up with an other alternative as well.
lsts = [[1, 2, 3], [4, 5], [6]]
delim = ['delim']
[x for t in zip(lsts,[delim]*len(lsts)) for x in t][:-1]
# Out[44]: [[1, 2, 3], ['delim'], [4, 5], ['delim'], [6]]

Combination of betting odds in Python

So I'm new to Python and I've decided to work on a project that I'm interested in. I've connected to an API to get betting odds from different bookies. I've successfully got the data and stored in a Sqlite3 database. The next step is to compare the odds, and this is where I'm getting stuck.
So let's say I have a list of odds from 3 bookies:
bookie1 = [1,2]
bookie2 = [3,4]
bookie3 = [5,6]
then I have the odds from all bookies in 1 list, such as:
bookies_all = [ [1,2], [3,4], [5,6] ]
How do I get the combinations of odds from the 3 bookies?
I expect the output to look something like this:
combos = [[1,3], [1,5], [1,4], [1,6], [2,3], [2,5], [2,4], [2,6], [3,5], [3,6],[4,5], [4,6]]
Is the best option to loop through the list?
I've coded this up and it gives me all the combinations I need.
bookies_all = [[1, 2], [3, 4], [5, 6]]
combos = []
count = 0
for outer in bookies_all:
for inner in bookies_all:
temp_list = [outer[0], inner[1]]
count += 1
combos.append(temp_list)
print(combos)
Output: [[1, 2], [1, 4], [1, 6], [3, 2], [3, 4], [3, 6], [5, 2], [5, 4], [5, 6]]
The combinations in bold are the ones I want. This code works for this example.
I will test it out for scenarios where the bookies_all list has more values.
You can use itertools.combinations to find the combinations of bookies, then use a list comprehension to interleave the items:
from itertools import combinations
bookies_all = [[1, 2], [3, 4], [5, 6]]
all_comb = list(combinations(bookies_all, 2))
#print(all_comb)
combos = [[i, j] for c in all_comb for i in c[0] for j in c[1]]
print(combos)
Output:
[[1, 3], [1, 4], [2, 3], [2, 4], [1, 5], [1, 6], [2, 5], [2, 6], [3, 5], [3, 6], [4, 5], [4, 6]]

Convert simple list comprehension into for loops

My objective is transform this list comprehension into for loops :
[[x * y for x in [1, 2]] for y in [3, 4, 5]]
# gives [[3,6], [4,8], [5,10]]
The only thing i can find :
List = []
for y in [3, 4, 5]:
for x in [1, 2]:
List.append([y * x])
# Gives [[3], [6], [4], [8], [5], [10]]
I feel silly but i struggle to find the solution.
You need a temporary list in between the for-loops:
List = []
for y in [3, 4, 5]:
l = []
for x in [1, 2]:
l.append(x*y)
List.append(l)
Output:
[[3, 6], [4, 8], [5, 10]]
Take out the square brackets
List = []
for y in [3, 4, 5]:
for x in [1, 2]:
List.append(y * x)
Adding a square bracket around a calculation makes it a list in python

A strange behavior when I append to a list in Python

I am looking for the Josephus_problem ,but the result is not my Expected. Why?
def J(n,x):
li=range(1,n+1)
k=0
res=[]
while len(li)>1:
k= (x+k-1) % len(li)
li.pop(k)
res.append(li)
#print li
return res
print J(5,3)
Expected Output:
[1, 2, 4, 5]
[2, 4, 5]
[2, 4]
[4]
Actual Output:
[[4], [4], [4], [4]]
You need to append copy of list here:
res.append(li[:]) # <-- not res.append(li) !!!
The actual reason of what's going on it that list is mutable data structure in Python. Look at this snippet
>>> l = [1,2,3]
>>> p = [l,l,l]
>>> p
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
>>> l.pop()
3
>>> p
[[1, 2], [1, 2], [1, 2]]

Categories