Given a String (x) containing only characters a-z, write a function (f)
that returns a base 10 integer, which converts the String as if it were
a base 26 numeral. Function f is bijective**.
Here are some example runs:
x | f(x) empty | 0 a | 1 b | 2 z | 26 aa | 27 az | 52 ba | 53 bz | 78 aaa | 703 aaz | 728 ... aza | 1353
Using your preferred programming language, implement function f.
* - it's known as Raf's problem and I saw it on Tony Morris `lambda blog
** - BUG: this function is injective since we can't use `spaces in number to string encoding ***
*** - we can make use of spaces if numeral separator is two-spaced but it is not what was asked - see example for encoding 26 and 27
Following is sample solutions done in Scala / Python / Haskell. Not sure about complexity level but it seems that python isn't shortest language anymore??
Haslell
str2num = foldl (\acc x -> acc * 26 + (ord x - (ord 'a') + 1)) 0
Scala
def str2num(str: String): Int = { val base = 26 val offset = 'a'.toInt -1 var res = 0 for (c <- str) { val digit = if (c == ' ') 0 else (c.toInt - offset) res = res * base + digit } res } def num2str(n: Int): String = { val base = 26 val offset = 'a'.toInt -1 def aux(n: Int): List[Char] = (n / base, n % base) match { case (0, 0) => List(' ') case (0, r) => List((r + offset).toChar) case (q, 0) => 'z' :: aux(q-1) case (q, r) => (r + offset).toChar :: aux(q) } val res = aux(n).reverse.mkString if (res == " ") res else res.trim } test("Raf's Problem"){ // x | f(x) val tests = Map ( " " -> 0, "a" -> 1, "b" -> 2, "z" -> 26, "aa" -> 27, "az" -> 52, "ba" -> 53, "bz" -> 78, "aaa" -> 703, "aaz" -> 728, "aza" -> 1353) for (t <- tests) { println(t._1 + " -> " + t._2 + " => <" + num2str(t._2) + ">") assert(str2num(t._1) == t._2) assert(t._1 == num2str(t._2)) } }
Python
import string def code(number): if number>0 and number<27: return chr(number+96) def decode(s): if s in string.ascii_lowercase: return ord(s)-96 def coding(number): if number==0: return "" s=[] while number>0: x=number%26 if x==0: x=26 number=number-26 y=code(x) t=[y]+s s=t number=number/26 return ''.join(s).split()[0] def decoding(s): l=len(s) num=0 for i in s: if not i==' ': c=decode(i) num=num*26+c return num
Super python
#!/usr/bin/python from math import pow from sys import argv """Details 16.09.2010 Given a String (x) containing only characters a-z, write a function (f) that returns a base 10 integer, which converts the String as if it were a base 26 numeral. Function f is bijective. Nicu Marcu *.*@*-*.com """ letters=map(chr, range(97,123)) def str2num(text): to_str2num=[] for l in text: index=1 for ll in letters: if l == ll: to_str2num.append(index) index+=1 index=0 result=0 for l in reversed(to_str2num): p = int(pow(26,index)) result+=l*p index+=1 return result def num2str(nr): result=[] a = divmod(int(nr),26) rez = a[0] rest = a[1] if rez==0: result.append(rest) return result if rez==1 and rest==0: result.append(26) return result while(1): if rest==0: result.append(26) rez-=1 else: result.append(rest) if rez==0: return result if rez<=26: result.append(rez) return result break else: a = divmod(rez,26) rez = a[0] rest = a[1] def main(): funct = argv[1] arg = argv[2] if funct=="str2num": print str2num(arg) if funct=="num2str": a = reversed(num2str(arg)) world="" for i in a: world+=letters[i-1] print world return 1 main()
No comments:
Post a Comment