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.

Advertisements

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]
    
    

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: