Python set
s are magical things. Mutable, deduplicating data stores with handy operator overloads for &
, ^
and |
.
Specifically among the others, set
s overload the &
operator to do mutual membership tests like so:
>>> set("aasd") & set("aabc")
{'a'}
What to do? Why, spin my own, of course!
def membertester(a, b):
"""a slow (iterative) dupe-preserving sorting subset tester,
for mutual membership tests (like set overloads &)"""
c = []
a, b = sorted(list(a)), sorted(list(b))
(l, maxl, s, minl) = {
True: (a, len(a), b, len(b)),
False: (b, len(b), a, len(a))
}[ len(a) >= len(b) ]
for i in range(maxl):
try:
if s.count(l[i]) >= l.count(l[i]):
c.append(a[i])
except IndexError:
pass
return c
How it works, because it might be a little cryptic:
- Retrieve the longer and shorter of the two sorted lists, and their lengths, using a switch statement.
- For each item in the longer range, take note of the item if the number of occurences of the same item in the short list is greater than or equal to the number of occurences of the item in the longer list.
Used as above:
>>> membertest("aasd", "aabc")
['a', 'a']
Success!
How can I improve it? Is there a faster or more efficient way, or perhaps a less flimsy algorithm?
Assertions that should pass:
assert membertest("a" * 6, '') == []
assert membertest("abdeg", "rrertabasdddhjkdeg") == ['a', 'b', 'd', 'e', 'g']
assert membertest("abddeg", "rrertabasdddhjkdeg") == ['a', 'b', 'd', 'd', 'e', 'g']
An inconsistency I don't understand, but which is definitely a bug:
>>> is_subset('10', '122')
['0']
>>> is_subset("ab", "acc")
['a']
I don't understand this in the slightest.
I wrote this function specifically for use with A-Za-z
, so numbers in strings was an oversight I didn't consider.
The other bugs noted in @alexwchan's great answer are definitely not intentional.