Task: Textonyms




Go: package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"strings"
	"unicode"
)

func main() {
	log.SetFlags(0)
	log.SetPrefix("textonyms: ")

	wordlist := flag.String("wordlist", "wordlist", "file containing the list of words to check")
	flag.Parse()
	if flag.NArg() != 0 {
		flag.Usage()
		os.Exit(2)
	}

	t := NewTextonym(phoneMap)
	_, err := ReadFromFile(t, *wordlist)
	if err != nil {
		log.Fatal(err)
	}
	t.Report(os.Stdout, *wordlist)
}


var phoneMap = map[byte][]rune{
	'2': []rune("ABC"),
	'3': []rune("DEF"),
	'4': []rune("GHI"),
	'5': []rune("JKL"),
	'6': []rune("MNO"),
	'7': []rune("PQRS"),
	'8': []rune("TUV"),
	'9': []rune("WXYZ"),
}




func ReadFromFile(r io.ReaderFrom, filename string) (int64, error) {
	f, err := os.Open(filename)
	if err != nil {
		return 0, err
	}
	n, err := r.ReadFrom(f)
	if cerr := f.Close(); err == nil && cerr != nil {
		err = cerr
	}
	return n, err
}

type Textonym struct {
	numberMap map[string][]string 
	letterMap map[rune]byte       
	count     int                 
	textonyms int                 
}

func NewTextonym(dm map[byte][]rune) *Textonym {
	lm := make(map[rune]byte, 26)
	for d, ll := range dm {
		for _, l := range ll {
			lm[l] = d
		}
	}
	return &Textonym{letterMap: lm}
}

func (t *Textonym) ReadFrom(r io.Reader) (n int64, err error) {
	t.numberMap = make(map[string][]string)
	buf := make([]byte, 0, 32)
	sc := bufio.NewScanner(r)
	sc.Split(bufio.ScanWords)
scan:
	for sc.Scan() {
		buf = buf[:0]
		word := sc.Text()

		
		
		
		n += int64(len(word)) + 1

		for _, r := range word {
			d, ok := t.letterMap[unicode.ToUpper(r)]
			if !ok {
				
				continue scan
			}
			buf = append(buf, d)
		}
		
		num := string(buf)
		t.numberMap[num] = append(t.numberMap[num], word)
		t.count++
		if len(t.numberMap[num]) == 2 {
			t.textonyms++
		}
		
	}
	return n, sc.Err()
}

func (t *Textonym) Most() (most int, subset map[string][]string) {
	for k, v := range t.numberMap {
		switch {
		case len(v) > most:
			subset = make(map[string][]string)
			most = len(v)
			fallthrough
		case len(v) == most:
			subset[k] = v
		}
	}
	return most, subset
}

func (t *Textonym) Report(w io.Writer, name string) {
	
	fmt.Fprintf(w, `
There are %v words in %q which can be represented by the digit key mapping.
They require %v digit combinations to represent them.
%v digit combinations represent Textonyms.
`,
		t.count, name, len(t.numberMap), t.textonyms)

	n, sub := t.Most()
	fmt.Fprintln(w, "\nThe numbers mapping to the most words map to",
		n, "words each:")
	for k, v := range sub {
		fmt.Fprintln(w, "\t", k, "maps to:", strings.Join(v, ", "))
	}
}




Python: from collections import defaultdict
import urllib.request

CH2NUM = {ch: str(num) for num, chars in enumerate('abc def ghi jkl mno pqrs tuv wxyz'.split(), 2) for ch in chars}
URL = 'http://www.puzzlers.org/pub/wordlists/unixdict.txt'


def getwords(url):
 return urllib.request.urlopen(url).read().decode("utf-8").lower().split()

def mapnum2words(words):
    number2words = defaultdict(list)
    reject = 0
    for word in words:
        try:
            number2words[''.join(CH2NUM[ch] for ch in word)].append(word)
        except KeyError:
            
            reject += 1
    return dict(number2words), reject

def interactiveconversions():
    global inp, ch, num
    while True:
        inp = input("\nType a number or a word to get the translation and textonyms: ").strip().lower()
        if inp:
            if all(ch in '23456789' for ch in inp):
                if inp in num2words:
                    print("  Number {0} has the following textonyms in the dictionary: {1}".format(inp, ', '.join(
                        num2words[inp])))
                else:
                    print("  Number {0} has no textonyms in the dictionary.".format(inp))
            elif all(ch in CH2NUM for ch in inp):
                num = ''.join(CH2NUM[ch] for ch in inp)
                print("  Word {0} is{1} in the dictionary and is number {2} with textonyms: {3}".format(
                    inp, ('' if inp in wordset else "n't"), num, ', '.join(num2words[num])))
            else:
                print("  I don't understand %r" % inp)
        else:
            print("Thank you")
            break


if __name__ == '__main__':
    words = getwords(URL)
    print("Read %i words from %r" % (len(words), URL))
    wordset = set(words)
    num2words, reject = mapnum2words(words)
    morethan1word = sum(1 for w in num2words if len(num2words[w]) > 1)
    maxwordpernum = max(len(values) for values in num2words.values())
    print(.format(len(words) - reject, URL, len(num2words), morethan1word))

    print("\nThe numbers mapping to the most words map to %i words each:" % maxwordpernum)
    maxwpn = sorted((key, val) for key, val in num2words.items() if len(val) == maxwordpernum)
    for num, wrds in maxwpn:
        print("  %s maps to: %s" % (num, ', '.join(wrds)))

    interactiveconversions()