# If you knew …, then you could work out …

Jim Randell has developed a neat generic subroutine called filter_unique that can assist teasers of the form “if you knew X, then you could work out what Y is”. He has made this and other useful routines for solving teasers available in his enigma.py library, which is also available here. I call my version of Jim’s subroutine partition_unique because ‘filter’ implies for me that the output returns only a part of the input whereas ‘partition’ implies that the output divides the input into parts. My version is as follows:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
from collections import defaultdict from inspect import signature # Partition the items in the input sequence (seq) into two # sequences such that for items in them f(s) does and does # not imply g(s) (requires Python 3.6 or later versions) def partition_unique(seq, f=lambda x:x, g= lambda x:x): unpack = lambda f: (lambda x: f(*x)) if len(signature(f).parameters) > 1: f = unpack(f) if len(signature(g).parameters) > 1: g = unpack(g) f_to_g_map = defaultdict(lambda :defaultdict(list)) for item in seq: f_to_g_map[f(item)][g(item)].append(item) unique, not_unique = [], [] for gd in f_to_g_map.values(): t = unique if len(gd.keys()) == 1 else not_unique for x in gd.values(): t.extend(x) return unique, not_unique |

It is available here.

An interesting aspect of this implementation is that it uses the original coding that I adopted soon after seeing Jim’s initial version. However, I abandoned this version in favour of Jim’s because mine had the undesirable property of not maintaining the order of elements in the input sequence in its output sequences. This was the result of the fact that Python dictionaries did not then return keys in a specified order.

But this has now changed in Python 3.6 and it has recently been announced that dictionaries in future versions of Python will return their keys in insertion order, a new feature which neatly removes the weakness that had caused me to drop my original coding for this routine.

### Examples of Use

Here is a teaser that illustrates the use of partition_unique:

—————————————————————————

Sunday Times Teaser 2857 by Danny Roth

Published June 25 2017

Significant Errors

Last year George and Martha were going to visit one of their daughters. Her

house number was a two-figure number but unfortunately Martha wrote the

number incorrectly by making the first digit less than it should be. When

George discovered the error he commented that the incorrect number was a

whole number percentage of the correct one. If you knew that percentage

then you should be able to work out their daughter’s house number.

Then the daughter moved to a different two-figure house number, Martha

again wrote the number incorrectly by making the first digit less than it

should be, and again the incorrect number was a whole number percentage of

the correct one. If you knew that percentage then you should be able to

work out their daughter’s new house number.

What was the daughter’s original house number, and what is the new one?

—————————————————————————

which can be solved as follows:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
from partition_unique import partition_unique nps = [] # consider the daughter's posible house numbers for m in range(20, 100): # ... and the tens digit of the incorrect one for i in range(1, m // 10): n = 10 * i + m % 10 # look for integer percentages p, r = divmod(100 * n, m) if not r: nps.append((p, m, n)) # given an item (percentage, house_number, incorrect_number) # return the percentage f = lambda p, m, n: p # given an item (percentage, house_number, incorrect_number) # return the house number g = lambda p, m, n: m # find a percentage for which the associated house number is unique n1 = partition_unique(nps, f, g)[0] # remove the first house number and repeat to find the second house number nps = [x for x in nps if x[1] != n1[0][1]] n2 = partition_unique(nps, f, g)[0] for i in (0, 1): print(f'first: {n1[i][1]} ({n1[i][2]}), second: {n2[0][1]} ({n2[0][2]})') |