Upside Up
May 27, 2011
This is an easy exercise for a lazy late-spring Friday afternoon. We take 0, 1, 6, 8 and 9 as the possible upside up digits:
(define (upside-up d)
(case d ((0) 0) ((1) 1) ((6) 9) ((8) 8) ((9) 6) (else #f)))
Then we map over the digits of the input, report #f if any have no upside, then recombine and check if the number is the same as its upside up reversal:
(define (upside-up? n)
(let ((ds (map upside-up (digits n))))
(if (member #f ds) #f
(= (undigits (reverse ds)) n))))
The next upside up number after 1961 is 6009, and there are 39 upside up numbers less than ten thousand:
> (let loop ((n 1962))
(if (upside-up? n) n
(loop (+ n 1))))
6009
> (length (filter upside-up? (range 10000)))
39
We used range, filter, digits, and undigits from the Standard Prelude. You can run the program at http://programmingpraxis.codepad.org/VYkXm2GM.
[…] today’s Programming Praxis exercise, our task is to write a function to determine if a number remains the […]
My Haskell solution (see http://bonsaicode.wordpress.com/2011/05/27/programming-praxis-upside-up/ for a version with comments):
upsideUp :: Show a => a -> Bool upsideUp n = and . zipWith isRot (show n) . reverse $ show n where isRot a b = maybe False (== b) . lookup a $ zip "01689" "01986" main :: IO () main = do print $ head (filter upsideUp [1962..]) == 6009 print $ length (filter upsideUp [0..9999]) == 39My Python solution:
#!/usr/bin/env python from itertools import count, ifilter UPSIDE_DICT = dict(zip("01689", "01986")) # matches digit to rotated version def is_upside_up(n): """Determines whether reads the same after being rotated 180 degrees""" digit_pairs = zip(str(n), str(n)[::-1]) return all(UPSIDE_DICT.get(x, False) == y for (x, y) in digit_pairs) def next_upside_up(n): """Next upside up number after n""" return next(ifilter(is_upside_up, count(n + 1))) if __name__ == "__main__": print next_upside_up(1961) print sum(1 for n in xrange(10000) if is_upside_up(n))I went through at least 3 different versions of
is_upside_up, making my solution less complicated each time; the first version was an imperative-style mess!My Try in REXX
count = 0 first = 1 do x = 1 to 10000 /* valid: only digits 1,6,8,9 */ /* 6 and 9 only in combination */ if verify(x,'1689','N') > 0 then iterate if (verify(x,'18','N') == 0) &, ((pos('6',x) > 0 & pos('9',x) > 0) |, (pos('6',x) == 0 & pos('9',x) == 0)) then do y = swap69(x) if x == reverse(y) then do count = count + 1 if x > 1691 & first == 1 then do say 'First No. > 1691 =' x first = 0 end end end end say 'there are' count 'upside up numbers between 1 and 10000' exit/*
First No. > 1691 = 1881
there are 12 upside up numbers between 1 and 10000
*/
and the Swap-Routine
swap69: procedure parse arg in out = translate(in,'s',6) /* 6 -> s */ out = translate(in,'n',9) /* 9 -> n */ out = translate(in,9,'s') /* s -> 9 */ out = translate(in,6,'n') /* n -> 6 */ return outSorry, copied confusing tries, this should be it:
count = 0 first = 1 do x = 1 to 10000 /* valid: only digits 1,6,8,9 */ /* 6 and 9 only in combination */ if verify(x,'1689','N') > 0 then iterate if (verify(x,'18','N') == 0) &, ((pos('6',x) > 0 & pos('9',x) > 0) |, (pos('6',x) == 0 & pos('9',x) == 0)) then do y = swap69(x) if x == reverse(y) then do count = count + 1 if x > 1691 & first == 1 then do say 'First No. > 1691 =' x first = 0 end end end end say 'there are' count 'upside up numbers between 1 and 10000' exit swap69: procedure parse arg in out = translate(in,'s',6) /* 6 -> s */ out = translate(out,'n',9) /* 9 -> n */ out = translate(out,9,'s') /* s -> 9 */ out = translate(out,6,'n') /* n -> 6 */ return outMy solution is pretty similar to Graham’s:
from itertools import count, ifilter UPTABLE = dict(zip('01689', '01986')) valid = lambda n: all(UPTABLE.get(x, None) == y for (x, y) in zip(str(n), reversed(str(n)))) print next(ifilter(valid, count(1962))) print len(filter(valid, range(int(1e4))))An inelegant solution to show them all for validation:
print [i for i in range(10000) if set(str(i)).issubset(‘01689’) and str(i)[::-1].replace(‘6′,’x’).replace(‘9′,’6’).replace(‘x’,’9′)==str(i)]
;;; Common Lisp:
;; 5 and 2 are clearly symetrical, as any 2¢ pocket calculator will
;; show you:
;;
;; _ _
;; |_ _|
;; _| |_
;;
;; But since the concensus seems to be to ignore them:
(defparameter *symetric-digits*
#((#\0) (#\1) () () () () (#\9) () (#\8) (#\6))
“A vector indexed by digits, containing lists of symetrical digits.”)
(defun upside-down-digit-p (a b)
(member a (aref *symetric-digits* (digit-char-p b))))
(defun upside-down-number-p (n &optional (base 10.))
(loop
:with digits = (format nil “~VR” base n)
:with last-index = (1- (length digits))
:for i :from 0 :to (truncate (length digits) 2)
:always (upside-down-digit-p (aref digits i) (aref digits (- last-index i)))))
(defun programming-praxis-2011-05-27 ()
(loop
:with first-upside-down = nil
:with count = 0
:for n :from 1962 :below 10000
:do (when (upside-down-number-p n)
(unless first-upside-down
(setf first-upside-down n))
(incf count))
:finally (return (values first-upside-down count))))
(programming-praxis-2011-05-27)
–> 6009
15
Cheating a bit by looking at the Python programs, but here’s one in Ruby …
UPSIDE_DICT = %w[0 1 6 8 9].zip(%w[0 1 9 8 6]) class Integer def upside? self.to_s.split(//).zip(self.to_s.split(//).reverse).inject(true) { |r,v| r && UPSIDE_DICT.include?(v) } end end (1..10000).each do |v| puts "#{v} is an upside number" if v.upside? endAnother variant using python:
from itertools import ifilter, imap, islice from operator import eq, methodcaller, Counter from string import maketrans # create a function that strips non-flipable digits (2,3,4,5,7) and flips the # flipable ones (e.g., 6 and 9). flipped = methodcaller('translate', maketrans('69','96'), '23457') def is_upside_up(n): s = str(n) return all(islice(imap(eq, s, flipped(s[::-1])), (len(s)+1)/2)) next(ifilter(is_upside_up, count(1692))) Counter(imap(is_upside_up, xrange(10000)))[…] 출처: https://programmingpraxis.com/2011/05/27/upside-up/ […]
Factor Programming language
CONSTANT: upside-up-xform H{ { 0 0 } { 1 1 } { 6 9 } { 8 8 } { 9 6 } } : reversed-digits ( n -- list ) { } swap [ dup 0 > ] [ 10 /mod swapd suffix swap ] while drop ; : list>number ( list -- n ) 0 [ swap 10 * + ] reduce ; : upside-up? ( n -- ? ) dup reversed-digits [ upside-up-xform at ] map [ ] filter list>number = ;( scratchpad ) 10000 iota [ upside-up? ] filter length .
39
For grins, here’s a Erlang implementation. I’m new to Erlang, so I’m sure there are other, better, ways to do it.
-module(upside). -export([is_upside_up/1, test/0]). is_upside_up(N) -> NL = integer_to_list(N), NL == flipped(NL,[]). flipped([$0| T], L) -> flipped(T,[$0|L]); flipped([$1| T], L) -> flipped(T,[$1|L]); flipped([$2| _], _) -> false; flipped([$3| _], _) -> false; flipped([$4| _], _) -> false; flipped([$5| _], _) -> false; flipped([$6| T], L) -> flipped(T,[$9|L]); flipped([$7| _], _) -> false; flipped([$8| T], L) -> flipped(T,[$8|L]); flipped([$9| T], L) -> flipped(T,[$6|L]); flipped([],L) -> L. test() -> UL = [X || X <- lists:seq(0,10000), is_upside_up(X)], {lists:nth(1, [N || N <- UL, N > 1961]), length(UL)}.I don’t understand why, sometimes, even though submission went good, the comment won’t show up…
;; Scheme
(define (upside-char=? x y)
(let ((yy (assoc x
'((#\0 #\0) (#\1 #\1) (#\2 #\5) (#\5 #\2) (#\6 #\9)
(#\8 #\8) (#\2 #\5)))))
(and yy (char=? y (cadr yy)))))
;
(define (upside-down? n)
(let* ((s (number->string n))
(l (string-length s)))
(let loop ((i 0) (j (1- l)))
(if (< i j)
(and
(upside-char=? (string-ref s i)
(string-ref s j))
(loop (1+ i) (1- j)))
(or (and (member (string-ref s i) '(#\0 #\1 #\8)) #t)
(> i j))))))
I went with building upside up numbers instead of looping 10,000 times and checking each one
def build(string, flips): if len(string) == 2: return [string + flips[string[1]] + flips[string[0]]] else: upsideUps = [] for key in flips.keys(): upsideUps += build(string + flips[key], flips) return upsideUps def main(): flips = {"0": "0", "1": "1", "6": "9", "8": "8", "9": "6"} upsideUps = build("", flips) upsideUps = sorted(upsideUps) for num in upsideUps: print num#include <stdio.h> // Upside up map of digits static char map[] = "01xxxx9x86"; int main(void) { int i, j; char s[5], r[5]; int n = 0; s[4] = r[4] = '\0'; for (i=1962; i<=9999; ++i) { sprintf(s, "%04d", i); for (j=0; j<4; ++j) r[j] = map[s[3-j] - '0']; if (strcmp(s, r) == 0) if (++n == 1) printf("First upside up number: %d\n", i); } printf("There are %d upside up numbers between 1962 and 9999\n", n); }function UpsideUp(N : Integer) : Boolean; const Map : array[0 .. 9] of Char = ('0', '1', '.', '.', '.', '.', '9', '.', '8', '6'); var sN : String; sR : String; C : PChar; begin sN := IntToStr(N); sR := ''; C := PChar(sN); while C^ <> #0 do begin sR := Map[StrToInt(C^)] + sR; Inc(C); end; Result := sN = sR; end;//C# Solution.
for (int i = 1961; i x == ‘1’ ||x == ‘6’ || x == ‘8’ ||x == ‘9’ ||x == ‘0’);
foreach (var item in j)
{
topupNo += item;
}
if (topupNo == i.ToString())
{
Console.WriteLine(i.ToString());
}
}
//C# Solution
. for (int i = 1961; i <= 10000; i++) {
string topupNo = string.Empty; var j = i.ToString().Replace("6", "T").Replace("9",
"6").Replace("T", "9").Reverse().Where(x => x == '1' ||x == '6' || x == '8' ||x
== '9' ||x == '0');
foreach (var item in j) { topupNo += item; }
if (topupNo == i.ToString()) { Console.WriteLine(i.ToString()); } }
Just cause there isn’t a version in Go yet.. It’s simple, but gets the job done:
package main import ( "fmt" "strconv" ) func Is_upside_up(test int) bool { transl := map[byte]byte{} in := "01689" out := "01986" for i := 0; i < len(in); i++ { transl[in[i]] = out[i] } teststr := strconv.Itoa(test) begin := 0 end := len(teststr) - 1 for begin <= end { if transl[teststr[begin]] != teststr[end] { return false } begin++; end-- } return true } func Next_upside_up(test int) int { test += 1 for !Is_upside_up(test) { test += 1 } return test } func main() { fmt.Println(Next_upside_up(1961)) var sum int for a := 0; a < 10000; a++ { if Is_upside_up(a) {sum += 1} } fmt.Println(sum) }