Optimierung der Telefontastatur

33

Es scheint diesen anhaltenden Wahnsinn zu geben, wenn Leute mühsam neue Tastaturlayouts wie Dvorak oder Neo erlernen, weil sie dadurch angeblich produktiver werden. Ich behaupte, dass das Wechseln des Tastaturlayouts eine schlechte Idee ist, da es Monate dauern kann, bis Sie auf dem neuesten Stand sind, und wenn Sie im Endeffekt 5% schneller als der Rest sind, sind Sie fertig, wenn Sie auf einem nicht kompatiblen Computer tippen müssen nicht deine eigene.

Außerdem vergessen all diese Menschen, wo der eigentliche Engpass in der modernen Kommunikation liegt - die Telefontastatur.

So sieht eine durchschnittliche Telefontastatur aus:

Die Telefontastatur

Buchstabe 'r' ist der dritte Buchstabe auf Knopf 7; Wenn Sie also auf einem Mobiltelefon den Buchstaben "r" eingeben, drücken Sie die Taste 7 dreimal, bei "s" viermal und bei "a" einmal die Taste 2.

In Anbetracht dessen war es wahrscheinlich eine schlechte Entscheidung, "e" nach "d" zu setzen - "e" ist der am häufigsten verwendete Buchstabe im englischen Alphabet. Wenn Sie also Knopf 3 "EDF" anstelle von "DEF" beschriften, haben Sie würde ziemlich viele Tastenanschläge sparen.

Darüber hinaus haben Sie wahrscheinlich selbst erlebt, dass die Eingabe von 2 Buchstaben, die dieselbe Schaltfläche haben, ein Ärgernis ist. Wenn Sie "TU" schreiben möchten, können Sie nicht einfach dreimal 8 drücken, da dies zu "V" führen würde. Normalerweise schreibst du 'T', drückst dann die Leertaste, drückst dann die Rücktaste und dann 'U', was 5 Tastendrücken anstelle von 3 entspricht.


TL; DR

Angesichts dieser beiden Regeln:

  • Ein Buchstabe wird durch n-maliges Drücken einer Taste eingegeben, wobei n die Position ist, an der sich der Buchstabe auf der Beschriftung der Taste befindet
  • Das Schreiben von zwei Buchstaben, die mit derselben Taste eingegeben wurden, erfordert zusätzliche 2 Tastendrücke

Wie sieht das Layout der Telefontastatur aus, bei dem bei einem bestimmten Text am wenigsten gedrückt werden muss? Sie sollten nur die Tasten 2-9 verwenden, 1 und 0 sind für spezielle Symbole reserviert.

Eingang

Der Text, für den Sie das optimale Layout finden sollten, wird über stdin geliefert. Sie müssen nichts anderes als das Kleinbuchstaben behandeln und können davon ausgehen, dass die Eingabe nur aus diesem besteht. Sie können auch davon ausgehen, dass der eingegebene Text ziemlich groß ist und jeder Buchstabe mindestens einmal darin enthalten ist, wenn dies hilfreich ist.

Ausgabe

Ich möchte die Ausgabe nicht zu stark einschränken, da dies manchmal einige Sprachen gegenüber anderen vorteilhafter macht. Wenn Ihre Sprache jedoch Arrays anzeigt, ist dies in Ordnung. Alternativ können Sie jedes Etikett mit einem Zeilenumbruch trennen.

Möglicherweise gibt es mehrere optimale Layouts. Sie können eines davon drucken. Hier ist ein einfaches Beispiel:

>> echo "jackdawslovemybigsphinxofquartz" | foo.sh
ojpt
avhz
cen
skm
dyf
wbq
ixu
lgr

Bonuspunkte

-35 wenn Ihr Algorithmus nicht alle möglichen Layouts brachial erzwingt (ich schaue hier auf Haskells `Permutationen ')

-3 wenn Ihr Code in eine Textnachricht passt (140 Zeichen) und Sie ein Bild von Ihnen posten, das Ihren Code an einen Freund sendet.

Dies ist meine erste Herausforderung bei StackExchange. Ich würde mich freuen zu hören, ob es Ihnen gefällt oder ob Sie ein anderes Feedback dazu haben!

Flonk
quelle
2
Willkommen auf CodeGolf.SE! Ich sehe kein Problem mit Ihrer Frage, aber es ist im Allgemeinen eine gute Idee, Ihre Herausforderung zuerst in der Sandbox zu veröffentlichen, um Feedback zu erhalten und Unklarheiten zu beseitigen, bevor Sie sie auf der Hauptseite veröffentlichen.
Martin Ender
Ah, das ist cool, ich werde es definitiv in Zukunft tun.
Flonk
1
Mein Telefon kann eine einzelne SMS mit 60 Zeichen senden, unterstützt Klammern jedoch nicht richtig. Bin ich nicht im Bonus?
ζ--
1
Gute Frage! Ich denke nicht, dass irgendjemand in der Lage sein wird, den -35 Bonus zu umgehen . Selbst wenn wir uns auf Layouts beschränken, die 4 Zeichen auf zwei der Tasten und 3 auf allen verbleibenden 6 Zeichen enthalten, gibt es 26! / (2! * 6!) = 280,063,514,671,253,913,600,000 > 2^77eindeutige Permutationen, bei denen die einfachen Neuanordnungen der Tasten nur einmal gezählt werden.
Dennis
2
Ich frage Sie auch, ob Sie die Anzahl der Tastendrücke Ihrer Lösung ausdrucken könnten. Also werden wir sehen, wer den Besten gefunden hat!
Antonio Ragagnin

Antworten:

5

Perl, 333

$_=<>;$c{$&}++while/./g;@c=sort{$c{$b}<=>$c{$a}}keys%c;$d{$&.$1}++while/.(?=(.))/g;sub f{my$x=shift;if(my$c=pop@$x){for(grep!$_[$_],0..7){my@y = @_;$y[$_]=$c;f([@$x],@y)}}else{for(0..7){$z=$_[$_];$c+=$d{$z.$_}+$d{$_.$z}for@{$a[$_]}}$c<$m?($m=$c,@n=@_):1}}while(@c){$m= ~0;f[splice@c,0,8];push@{$a[$_]},$n[$_]for 0..7}print@$_,$/for@a

Hier ist ein Versuch, für Regel # 2 zu optimieren. Nach meinem obigen Kommentar und anstelle von Antworten unter Berücksichtigung dieser Regel (vgl. Hohe Fragenbewertung) dachte ich, dass ich hier etwas Mühe schulde ...

Lösungen, die nicht für Regel 2 optimiert sind, können eine Ausgabe erzeugen, die weit vom Optimum entfernt ist. Ich habe langen natürlichen englischen Text ("Alice im Wunderland") überprüft, vorverarbeitet (nur Kleinbuchstaben) und z. B. Perl-Skript aus der Antwort von OJW

2: ermx
3: tdfz
4: alp
5: oub
6: ick
7: nwv
8: hgj
9: syq

er Alleine ruiniert es und einige andere Paare hätten niemals auf demselben Schlüssel enden dürfen ...

Übrigens zxqjvkbpfmygwculdrshnioatesind die Buchstaben von diesem Text aus in aufsteigender Reihenfolge sortiert.

Wenn wir versuchen, es auf einfache Weise zu lösen (in der Hoffnung auf einen Bonus von -35) und Buchstaben nacheinander zu platzieren, indem wir den verfügbaren Schlüssel nach einer minimalen Anzahl von Paaren auswählen, können wir beispielsweise mit Folgendem enden:

slbx
hdmz
nrf
iuj
ogv
awk
tcp
eyq

Ich poste hier keine Postleitzahl für diese (falsche) Lösung. ZB beachten Sie, cist häufiger als wund steht an erster Stelle. tc( ct) Paare sind offensichtlich seltener als ac( ca) - 43 + 235 gegenüber 202 + 355. Aber dann wendet es mit a- 598 + 88. Wir enden mit Paaren awund tc(964 insgesamt), obwohl es besser wäre acund tw(635 insgesamt). Etc..

Der nächste Algorithmus versucht also, alle 8 verbleibenden (oder 2, wenn zuletzt) ​​häufigsten Buchstaben mit den bereits auf der Tastatur befindlichen Buchstaben abzugleichen und sie so zu platzieren, dass die paarweise Anzahl minimal ist.

$_=<>;                          # Read STDIN.
$c{$&}++while/./g;              # Count letters (%c hash).
@c=sort{$c{$b}<=>$c{$a}}keys%c; # Sort them by frequency, ascending
$d{$&.$1}++while/.(?=(.))/g;    # (@c array), and count pairs (%d hash).

                                # Next is recursive sub that does the job.
                                # Some CPAN module for permutations
                                # would probably do better...
                                # Arguments are reference to array of what's 
                                # left un-placed of current 8-pack of letters,
sub f{                          # and 8 element list of placed letters
    my$x=shift;                 # (or undefs).
    if(my$c=pop@$x){            # Pop a letter from 8-pack (if anything left),
        for(grep!$_[$_],0..7){  # try placing it on each available key, and 
            my@y = @_;          # call sub again passing updated arguments.
            $y[$_]=$c;
            f([@$x],@y)
        }
    }else{                      # If, OTOH, 8-pack is exhausted, find sum of
        for(0..7){              # pairs count of current permutation (@_) and 
            $z=$_[$_];          # letters placed in previous rounds (8-packs).
                                # @a is "array of arrays" - note, we didn't 
                                # have to initialize it. First "8-pack" will
                                # be placed on empty keypad "automatically".
                                # We re-use undefined (i.e. 0) $c.

            $c+=$d{$z.$_}+$d{$_.$z}for@{$a[$_]}
        }
        $c<$m                   # Is sum for current placement minimal?
            ?($m=$c,@n=@_)      # Then remember this minimum and placement.
            :1
    }
}

while(@c){
    $m= ~0;                         # Initialize "minimum" with large enough 
    f[splice@c,0,8];                # number, then call sub with each 8-pack
                                    # (and empty list of placed letters 
                                    # from current round). On return,
                                    # @n will have optimal arrangement.
    push@{$a[$_]},$n[$_]for 0..7    # Then place it permanently on keypad.
}
print@$_,$/for@a                    # Show us what you've done.

Ergebnis ist:

sdfz
hlmx
nrv
iyp
ogk
acq
twb
euj

Ich mag das acPaar nicht (die Katze ist schließlich eine der Figuren), aber das ist immer noch die optimale Buchstabenplatzierung für Englisch, wenn mein Code nicht falsch ist. Nicht gerade "Golfen" Aufwand, nur eine funktionierende Lösung, hässlich oder nicht.

user2846289
quelle
3

Python3, es ist Montecarlo-Zeit!

Um dieses Problem zu lösen, zähle ich zuerst, wie viele "Klicks" Sie mit der Standardtastatur benötigen (ursprünglich:) abc,def,ghi,jkl,mno,pqrs,tuv,wxyz. Dann ändere ich diese Tastatur und überprüfe, ob sie billiger ist (der Text ist mit weniger Klicks geschrieben). Wenn diese Tastatur billiger ist, wird sie zur Standardtastatur. Ich iteriere diesen Vorgang 1Mmal.

Um die Tastatur zu ändern, entscheide ich zuerst, wie viele Änderungen vorgenommen werden sollen (die maximale Anzahl der Änderungen ist die Gesamtzahl der Buchstaben auf der Tastatur). Dann wähle ich für jeden Schalter zwei Knöpfe und zwei Positionen und übertrage ein Zeichen von der ersten auf die zweite Position.

Die maximale Anzahl von Schaltern pro Zeit ist die Anzahl der Buchstaben auf der Tastatur, da dies die minimale Anzahl von Änderungen ist, die Sie von zwei vollständig verschiedenen Tastaturen aus vornehmen müssen. (Ich möchte, dass es immer möglich ist, von einer Tastatur zu einer anderen zu wechseln.)

Die Ausgabe von echo "jackdawslovemybigsphinxofquartz" | python .\myscript.pyist:

61 ['anb', 'sef', 'hjc', 'iykl', 'odm', 'qgr', 'tuxv', 'wpz']

Wo 61ist die Anzahl der gedrückten Tasten, um eine bestimmte Nachricht zu verfassen?

Zeichen (keine Leerzeichen und keine Kommentare): 577

Ich weiß, es ist lang, aber ich bin wirklich neu in diesem Zeug.

from random import *
S=['abc','def','ghi','jkl','mno','pqrs','tuv','wxyz']
def P(L): # perform a switch of the keys of the keyboard:to switch from a given keyboard to another, the maximum number of exchanges is the number of the keys.
    R=randint
    N = len(''.join(L))
    W = randint(1,N)   # decide how many switches to perform
    EL = list(L)
    for i in range(0,W):
        B1=R(0,len(EL)-1)   # decide what buttons are considered in the switch
        B2=R(0,len(EL)-1)
        if len(EL[B1])==0: continue   
        P1=R(0,len(EL[B1])-1)       # decide what letter to switch and where
        if len(EL[B2])==0: P2=0
        else:   P2=R(0,len(EL[B2])-1)
        C1 = EL[B1][P1]     
        EL[B1]=EL[B1].replace(C1,'')
        EL[B2]=EL[B2][:P2]+C1+EL[B2][P2:]
    return EL
def U(L,X): # count how many clicks you need to compose the text X
    S=0
    Z=' '
    for A in X:
        for T in L:
            if A in T and Z not in T: S+=1+T.index(A)
            if A in T and Z in T: S+=3+T.index(A) # if the last character was in the same button..here the penality!
        Z=A
    return S
X=input()
n_iter=10**6
L = list(S)
cc=U(L,X)
print(cc,L)
for i in range(0,n_iter): #do some montecarlo stuff
    cc=U(L,X)
    pl=P(L)
    pc=U(pl,X)
    if(cc>pc):
        L=pl 
        print(pc,L)

Ich fand es so lustig, dass ich mich entschied, diesen Algorithmus mit LO HOBBIT auszuprobieren (ich habe auch ein Original zu Hause!). Es hat 383964Buchstaben und dies sind die paar Klicks gegen Tastatur , die ich finde:

909007 ['abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
879344 ['abkc', 'def', 'gqhi', 'jl', 'mno', 'rs', 'tupv', 'wxyz']
861867 ['abg', 'def', 'qhyi', 'jcl', 'mno', 'r', 'tupxv', 'swkz']
851364 ['abg', 'e', 'qchi', 'jyl', 'mn', 'dr', 'tupxv', 'sowkfz']
829451 ['ag', 'ef', 'qchi', 'jyl', 'mn', 'dbr', 'tupxv', 'sowkz']
815213 ['amg', 'ef', 'qch', 'ojyl', 'i', 'dbnr', 'tupxv', 'swkz']
805521 ['amg', 'ef', 'ch', 'ojyl', 'qi', 'dbnr', 'tupxv', 'swkz']
773046 ['amg', 'ef', 'ch', 'ojyl', 'qi', 'bnr', 'tupxv', 'dswkz']
759208 ['amg', 'eqf', 'ch', 'ojyl', 'i', 'bnr', 'tupxv', 'dswkz']
746711 ['ag', 'ekq', 'clh', 'sojy', 'bi', 'nmfr', 'tupxv', 'dwz']
743541 ['ag', 'ekq', 'clh', 'sojy', 'bi', 'nmfr', 'tpxv', 'dwuz']
743389 ['ag', 'ekq', 'clh', 'sojy', 'i', 'nmfr', 'tpxbv', 'dwuz']
734431 ['ag', 'ekq', 'lh', 'sjy', 'ci', 'nrf', 'tpxbv', 'dowumz']
705730 ['ag', 'oekq', 'lh', 'sjy', 'ci', 'nrf', 'tpxbv', 'dwumz']
691669 ['ag', 'oekq', 'lh', 'nsjy', 'ic', 'rf', 'tpxbv', 'dwumz']
665866 ['ag', 'hokq', 'el', 'nsjy', 'ic', 'rbf', 'tpxv', 'dwumz']
661610 ['agm', 'hokq', 'e', 'nsj', 'ilc', 'rbf', 'tpyxv', 'dwuz']

Ich behaupte also, das letzte ist eine der praktischsten Tastaturen (in Bezug auf Klicks).

Antonio Ragagnin
quelle
Woher weißt du, ob es optimal ist?
PyRulez
Montecarlo funktioniert nicht auf diese Weise. Es bringt Sie nur der optimalen Lösung näher und näher. Aber sagen wir mal, wenn sich in 1 Million Versuchen Ihre Lösung nicht ändert ... dann verwenden Sie wahrscheinlich die optimale. (oder Sie bewegen sich nicht genug von diesem "lokalen Minimum")
Antonio Ragagnin
Für Herausforderungen brauchen wir es also nur, um die meiste Zeit zu arbeiten?
PyRulez
1
@PyRulez Ich erkannte, dass dies kein einfaches Problem sein würde, um eine optimale Lösung zu finden (es sei denn, Sie versuchen alle möglichen Lösungen, die ich mit diesem -35-Bonus verhindern wollte).
Flonk
1
Interessante Methode, aber vielleicht ist diese Aufgabe nicht genau ihre Domäne. Ich habe überprüft, und für "Alice" erfordert die Standardtastatur 291613 Klicks. Mit meinem Programm optimiert - 195597. Mit dem Monte-Carlo-Ansatz habe ich in mehr als 5 Millionen Iterationen nicht weniger als 207000 Klicks erzielt. Und es ist besser, Buchstaben zu tauschen, dh das Layout 2x4 + 6x3 bleibt konstant.
user2846289
2

Nun, wenn Sie nur die beliebtesten Zeichen für die Klassen 2 bis 9 haben möchten, kann Perl dies in 127 Zeichen tun ...

foreach(split /\s*/,<>){$x{$_}++}
foreach(sort{$x{$b}<=>$x{$a}}keys %x){$o{$n++%8}.=$_}
for(0..7){printf "%d: %s\n",$_+2,$o{$_}}

etwas geben wie:

echo "jackdawslovemybigsphinxofquartz" | perl ./keypad.pl
2: ajeb
3: iynz
4: suv
5: ohm
6: wkl
7: rgp
8: xfc
9: dtq

Oder drucken Sie alles in einer Zeile aus und entfernen Sie 12 Zeichen:

foreach(split /\s*/,<>){$x{$_}++}
foreach(sort{$x{$b}<=>$x{$a}}keys %x){$o[$n++%8].=$_}
print join",",values@o,"\n";
OJW
quelle
2
Sie können dies leicht auf 100 Zeichen trimmen:$x{$_}++for split/\s*/,<>;map$o{$n++%8}.=$_,sort{$x{$b}<=>$x{$a}}keys%x;print map"$_:".$o{$_-2},2..9
Ardnew
1

Haskell, 160 - 35 = 125

import Data.List
import GHC.Exts
main=interact f where f s=show$transpose$map($sortWith(\x->length$filter(/=x)s)['a'..'z'])[t,t.d,t.d.d,d.d.d];t=take 8;d=drop 8

Beispiel:

$ runhaskell % <<< "jackdaws loves my big sphinx of quartz"
["afpy","sgqz","ihr","ojt","bku","clv","dmw","enx"]
$ </usr/share/dict/propernames tr A-Z a-z | runhaskell % 
["atjx","edgq","rhb","nmp","iyv","lcf","ouw","skz"]

Man könnte argumentieren, dass dies nicht für Regel 2 optimiert, sondern die häufigsten Buchstaben auf verschiedene Schlüssel legt .

mniip
quelle
0

JavaScript, 192 - 35 = 157

Ich habe gerade die Regel für sich wiederholende Zeichen bemerkt. das berücksichtigt das nicht. Aber wie @mniip in seiner Antwort vermerkte:

Man könnte argumentieren, dass dies nicht für Regel 2 optimiert, sondern die häufigsten Buchstaben auf verschiedene Schlüssel legt .

o={}
a=[]
b=['','','','','','','','']
i=-1
s.split('').forEach(function(x){o[x]=o[x]?o[x]+1:1})
for(x in o)a.push([o[x],x])
a.sort().reverse().forEach(function(x){b[i=(i+1)%8]+=x[1]})
alert(b)

Dies wäre wahrscheinlich in Ruby gewesen, aber ich bin nicht zu Hause und muss den Internet Explorer (eww) verwenden. Aber hey, es macht manchmal Spaß, Sprachen zu benutzen, die beim Golfen schrecklich sind! ;)

Beispielausgabe (für Ihre Eingabe):

avlc,sukb,otj,irh,zqg,ypf,xne,wmd

Da JS kein STDIN hat, geht das Programm davon aus, dass die Eingabe in einer Variablen gespeichert ist s.

Türknauf
quelle
Optimieren Sie auch diesbezüglich: "Das Schreiben von zwei Buchstaben, die mit derselben Taste eingegeben werden, erfordert zwei zusätzliche Tastendrücke"
Digital Trauma,
Betreff: Letzte Änderung. Ich finde die Ausgabe für 'abcdefghia'nicht gerade optimal.
user2846289
@VadimR "Sie können auch davon ausgehen, dass der Eingabetext ausreichend groß ist und jeder Buchstabe mindestens einmal darin enthalten ist."
Türklinke
Ich kenne. 'azbcdefghizjklmnopqzrstuvwxyz'
user2846289
1
Sie können b=['','','','','','','','']nach b=[x='',x,x,x,x,x,x,x], s.split('')nach s.split(x)und o[x]=o[x]?o[x]+1:1nach optimieren o[x]=-~o[x].
Zahnbürste
0

Python (119-35 = 84):

Angenommen, die Zeichenfolge ist eine Variable a und enthält nur Kleinbuchstaben:

for h in range(8): print h+2,zip(*sorted([(__import__("collections").Counter(a)[d],d) for d in set(a)])[::-1])[1][h::8]

ungolfed:

import collections

#a="jackdawslovemybigsphinxofquartz"
a=__import__("string").lowercase

b=collections.Counter(a)

c=set(a)

d=[(b[d],d) for d in c]

e=sorted(d)

f=e[::-1]

g=zip(*f)[1]

for h in range(8): print h+2,g[h::8]

PYG (76-35 = 41):

Aaah, wir können den enormen Import fallen lassen. Auch hier wird davon ausgegangen, dass sich die abisolierte Zeichenfolge in einem befindet.

for h in R(8): print h+2,Z(*S([(CC(a)[d],d) for d in Se(a)])[::-1])[1][h::8]
ɐɔıɐɔuʇǝɥʇs
quelle