Please improve these comprehensions (was meaning of [ ])
Rustom Mody
rustompmody at gmail.com
Mon Sep 4 14:16:02 EDT 2017
Since these discussions are uselessly abstract and meta
Here is some code I (tried) to write in class the other day
The basic problem is of generating combinations
Using the pascal-identity nCr + nC(r-1) = (n+1)Cr
This can be written (Haskell)
c :: Int -> Int -> Int
c n 0 = 1
c 0 (r+1) = 0
c (n+1) (r+1) = c n r + c n (r+1)
But I dont want NUMBER of combinations I want to generate combinations from
a given set
So change the spec to
c :: [a] -> Int -> [[a]]
ie n stops being a number but is now a set (here list) length n
c n 0 = [[]]
c [] (r+1) = []
c (x:xs) (r+1) = [x:l | l <- c xs r] ++ c xs (r+1)
Runs
? c [1,2,3,4] 2
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]] :: [[Int]]
All binomials
? [c [1,2,3,4] r | r <- [0..4]]
[
[[]],
[[1], [2], [3], [4]],
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]],
[[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]],
[[1, 2, 3, 4]]
] :: [[[Int]]]
Now thats neat as far as it goes but combinations are fundamentally sets
not lists
So I thought python would do a better job
I tried translating it to python and sets but it turned out more annoying than
helpful
Can someone improve it??
The straightforward translation of the above
Which is ok so far
def c(n,r):
if r == 0:
return [[]]
elif len(n) == 0:
return []
else:
return [[n[0]] + l for l in c(n[1:],r-1)] + c(n[1:],r)
Now to go from returning list of lists to set of sets:
st = frozenset
nullset = st([])
def singleton(x): return st([x])
def splitset(s):
i = iter(s)
e = next(i)
new = st(i)
return e,new
def cs(n,r):
""" Set version of c"""
if r == 0 :
return singleton(nullset)
elif len(n) == 0 :
return nullset
else:
x,xs = splitset(n)
return st([(singleton(x) | l) for l in cs(xs,r-1)]) | cs(xs,r)
def ss0n(fs):
""" Shows a simple-set (ie set-0, contains no subsets) nicely"""
r = "{"
for x in fs:
r += repr(x) + ", "
return r + "}"
def ss1n(fs0):
""" Shows a set-of-sets (ie set-1, contents are sets) nicely"""
r = "{"
for x in fs0:
r += ss0n(x) + ", "
return r + "}"
>>> cs({1,2,3,4}, 2)
frozenset([frozenset([2, 4]), frozenset([3, 4]), frozenset([2, 3]), frozenset([1, 3]), frozenset([1, 2]), frozenset([1, 4])])
>>> ss1n(cs({1,2,3,4}, 2))
'{{2, 4, }, {3, 4, }, {2, 3, }, {1, 3, }, {1, 2, }, {1, 4, }, }'
>>> ss1n(cs({1,2,3,4}, 2))
'{{2, 4, }, {3, 4, }, {2, 3, }, {1, 3, }, {1, 2, }, {1, 4, }, }'
So how could this be done better?
Here for reference is an abstract math ideal I would like to approximate
c : {t} → Int → {{t}} ## t is an arbitrary unspecified type
c n 0 = {{}}
c {} (r+1) = {}
c ({x} ∪ xs) (r+1) = {{x} ∪ l | l ∈ c xs r} ∪ c xs (r+1)
exactly parallel to the pascal identity
c n 0 = 1
c 0 (r+1) = 0
c (n+1) (r+1) = c n r + c n (r+1)
More information about the Python-list
mailing list