## Phone Numbers

### August 15, 2017

Here is our solution:

```(define (phone-numbers len skips)
(let loop ((len (- len 1))
(nums (map list (list-minus (range 1 10) skips))))
(if (zero? len)
(map undigits (map reverse nums))
(loop (- len 1)
(mappend (lambda (xs)
(filter (lambda (xs)
(not (= (car xs) (cadr xs))))
(map (lambda (x)
(cons x xs))
(list-minus (range 10) (cons 4 skips)))))
nums)))))```

That packs a lot into a little space. `Nums` is initially a list of lists of the possible first digits, excluding 0 and any digits in the `skips` list; the list is extended with an additional digit at each pass through `loop`. When `len` reduces to zero, the accumulated `nums` is reformatted as numbers, using two nested maps, then returned. Otherwise, while `len` is still positive, the two nested implicit loops of `mappend` and `map` extend each number in the list by another digit. `Mappend` is used because each member of the input list may be extended into several members of the output list. `Filter` removes any consecutive duplicates, and `map` adds new digits after adding digit 4 to the skip list. Whew!

Here’s a sample run:

```> (phone-numbers 3 '(1 3 5 7 9))
(202 206 208 260 262 268 280 282 286 402 406 408 420 426 428
460 462 468 480 482 486 602 606 608 620 626 628 680 682 686
802 806 808 820 826 828 860 862 868)```

You can run the program at http://ideone.com/bGBXHD.

Pages: 1 2

### 3 Responses to “Phone Numbers”

1. Similar approach – but in perl..

```use strict;
my \$n = shift;
my %T = map { (\$_,1) } 4, @ARGV;
my @D = grep { ! exists \$T{\$_} } 1..9; # List of digits not including 0+4 and ones listed...

print join q( ), map { gen( \$n-1, \$_ ) } sort 4,@D; # Loop through 4 and digits above
print "\n";

sub gen {
my(\$l,\$s) = @_;
\$l--;
# Skip if the same o/w call gen again if more digits to add for 0 and digits above...
return map { (\$_ eq substr \$s, -1) ? () : \$l ? gen(\$l,"\$s\$_") : "\$s\$_" } 0, @D;
}
```
2. Paul said

In Python.

```from itertools import filterfalse
ALL = list(range(10))

def tel_nums(length, excl, number=None):
if length == 0:
yield "".join(map(str,number))
elif number is None:
for n in filterfalse((excl + (0,)).__contains__, ALL):
yield from tel_nums(length-1, excl+(4,), [n])
else:
for n in filterfalse((excl + (number[-1],)).__contains__, ALL):
yield from tel_nums(length-1, excl, number+[n])
```
3. V said

Solution in Ruby. Generates all numbers of n length first then select the ones that match the rules.

```
def generate(n=3, black_list=[])
(0..9).to_a.
repeated_permutation(n).
select { |xs| valid?(xs, black_list) }.
map(&:join).
map(&:to_i)
end

def valid?(xs, black_list)
xs.first != 0 &&
!xs[1..-1].include?(4) &&
xs[0..-2].zip(xs[1..-1]).map { |a,b| a != b }.all? &&
xs - black_list == xs
end

generate(3,  [1, 3, 5, 7, 9])

```

outputs:

```
[202, 206, 208, 260, 262, 268, 280, 282, 286, 402, 406, 408, 420, 426, 428, 460, 462, 468, 480,
482, 486, 602, 606, 608, 620, 626, 628, 680, 682, 686, 802, 806, 808, 820, 826, 828, 860, 862, 868]

```