Il fantastico sistema di smistamento di Crazy Librarian


21

È tornato alla stagione scolastica! Quindi, per un lavoro part-time, stai aiutando nella biblioteca della scuola. Il problema è che il capo bibliotecario non ha mai nemmeno sentito le parole "Dewey Decimal" e tanto meno implementato quel sistema. Invece, il sistema di smistamento in uso è cresciuto "organicamente" man mano che la biblioteca si espande ...

Nel tentativo di mantenere la sanità mentale, hai scelto di scrivere un programma per aiutarti a ordinare i libri quando vengono restituiti, perché guai a te se smetti di ordinare i libri in modo errato. (Il capo bibliotecario è MOLTO severo.)

Input Output

  • L'input sarà un elenco di (ipotetici) titoli di libri, uno per riga, da STDIN / equivalente linguistico.
  • Puoi assumere non più di 100 libri alla volta (puoi portarne solo tanti in giro per la biblioteca contemporaneamente).
  • I libri possono contenere più parole nei titoli e queste parole possono essere separate da spazi o altri segni di punteggiatura (ad es. Due punti :, un trattino -, ecc.).
  • Per facilità di calcolo, supponiamo che tutti i titoli siano UTF-8.

L'output è gli stessi titoli, ordinati secondo le regole seguenti, sempre uno per riga, in STDOUT / equivalente lingua.

Le regole di classificazione

I libri sono ordinati numericamente in base al loro valore medio dei caratteri (ovvero, il valore cumulativo dei caratteri ha diviso il numero di caratteri nel titolo del libro), conteggiato dalle seguenti regole:

  • Tutti i personaggi contano per determinare il numero di caratteri in un titolo.
  • Le lettere minuscole sono contate dalla loro posizione nell'alfabeto. (A = 1, b = 2, ... z = 26)
  • Se il titolo contiene lettere maiuscole, queste contano per 1,5 il loro valore minuscolo (A = 1,5, B = 3, ... Z = 39). ("Le lettere maiuscole sono importanti!" Dice il bibliotecario.)
  • Ogni segno / simbolo di punteggiatura in questo elenco !@#$%^&*()-=_+[]\{}|;':",./<>?~conta -1 dal valore cumulativo prima della media. ("I titoli grandiosi non lo sono!")
  • Se il titolo contiene un numero, scritto in numeri arabi , quel numero viene sottratto dal valore medio prima dell'ordinamento. Le cifre consecutive multiple vengono trattate come un numero (ad esempio, 42sottrarre 42, non sottrarre 4 e quindi sottrarre 2). Le singole cifre non contano per il valore cumulativo (ovvero ogni cifra contribuisce a 0), ma contano il numero di caratteri. Si noti che ciò può comportare un valore negativo e deve essere trattato in modo appropriato. (Si dice che il bibliotecario abbia avuto una cotta per un istruttore di matematica da diversi anni, ormai.)
  • Se il titolo contiene due parole separate che iniziano con una R, il libro ottiene un punteggio di "infinito" e viene scaricato in una pila nell'angolo (cioè, disposto in modo casuale alla fine dell'elenco). (Una volta il bibliotecario è stato scaricato da una persona con quelle iniziali, o almeno così hai sentito.)
  • Gli spazi non contano per il valore cumulativo del carattere (ovvero, contribuiscono 0), ma contribuiscono al numero di caratteri in un titolo.
  • I caratteri che non soddisfano le regole di cui sopra (ad es. A ÿ) non contano per il valore cumulativo del carattere (ovvero, contribuiscono con 0), ma contribuiscono al numero di caratteri in un titolo.
  • Ad esempio, un libro ipotetico ÿÿÿÿÿavrebbe una "partitura" di (0+0+0+0+0) / 5 = 0, ma un libro ipotetico ÿÿyÿÿavrebbe una "partitura" di (0+0+25+0+0) / 5 = 5.
  • Due libri che capita di "segnare" lo stesso possono essere prodotti nella tua scelta d'ordine. (Sono sullo stesso scaffale, comunque)

Esempio di input 1

War and Peace
Reading Rainbow: The Best Unicorn Ever
Maus
Home for a Bunny

Esempio di output 1 (con "punteggi" tra parentesi per mostrare il ragionamento - non è necessario stamparli)

War and Peace (8.5)
Home for a Bunny (10.125)
Maus (15.125)
Reading Rainbow: The Best Unicorn Ever (infinity)

Esempio di input 2

Matthew
Mark
Luke
John
Revelations

Esempio di output 2 (con "punteggi" tra parentesi per mostrare il ragionamento - non è necessario stamparli)

Mark (12.375)
John (13)
Revelations (13.545454...)
Luke (13.75)
Matthew (~13.786)

Esempio di input 3

42
9 Kings
1:8
7th

Esempio di output 3 (con "punteggi" tra parentesi per mostrare il ragionamento - non è necessario stamparli)

42 (-42)
1:8 (-9.3333...)
9 Kings (~0.36)
7th (2.3333...)

Altre restrizioni

  • Questo è Code-Golf, perché è necessario mantenere il programma segreto agli occhi sempre attenti del bibliotecario, e più piccolo è il programma, più facile è nasconderlo.
  • Si applicano le restrizioni standard sulle scappatoie
  • Non lasciare che il bibliotecario ti sorprenda a perdere tempo spendendo tutto il tuo tempo su PPCG.

Che cosa succede se due libri ottengono lo stesso punteggio. cioè ho lettura Rainbow e Ruby Rails
Kishan Kumar il

@KishanKumar In quella specifica istanza, "disposti in modo casuale alla fine dell'elenco" poiché sono entrambi a doppia R. In altre parole, fai la tua scelta. Nel caso generale, se due parole ottengono lo stesso punteggio, possono apparire in qualsiasi ordine l'una rispetto all'altra. Aggiungerò un proiettile per chiarirlo.
AdmBorkBork,

7
È necessaria una parola in modo che il sistema abbia un nome acronimo. Consiglio il Amazing Sorting System di Crazy Librarian: D
Geobits,

3
@Geobits Hai CLASS?
AdmBorkBork,

I numeri sono solo numeri decimali? E se ce ne sono diversi, vengono sottratti tutti separatamente?
Paŭlo Ebermann,

Risposte:


5

APL (132)

{⎕ML←3⋄⍵[⍋{2='R'+.=↑¨⍵⊂⍨⍵≠' ':!99⋄↑(+/⍎¨'0',⍵⊂⍨⍵∊⎕D)-⍨((+/∊1.5 1×(⍳×∊⍨)∘⍵¨G)-+/⍵∊(⎕UCS 32+⍳94)~'`',⎕D,∊G←(⊂⎕A),⊂⎕UCS 96+⍳26)÷⍴⍵}¨⍵]}

Poiché tutti gli altri stanno facendo la stessa cosa, anche questa è una funzione che accetta una serie di titoli e la restituisce ordinata, ad esempio:

      titles
┌─────────────┬──────────────────────────────────────┬────┬────────────────┬───────┬────┬────┬────┬───────────┬──┬───────┬───┬───┐
│War and Peace│Reading Rainbow: The Best Unicorn Ever│Maus│Home for a Bunny│Matthew│Mark│Luke│John│Revelations│42│9 Kings│1:8│7th│
└─────────────┴──────────────────────────────────────┴────┴────────────────┴───────┴────┴────┴────┴───────────┴──┴───────┴───┴───┘

      {⎕ML←3⋄⍵[⍋{2='R'+.=↑¨⍵⊂⍨⍵≠' ':!99⋄↑(+/⍎¨'0',⍵⊂⍨⍵∊⎕D)-⍨((+/∊1.5 1×(⍳×∊⍨)∘⍵¨G)-+/⍵∊(⎕UCS 32+⍳94)~'`',⎕D,∊G←(⊂⎕A),⊂⎕UCS 96+⍳26)÷⍴⍵}¨⍵]}titles
┌──┬───┬───────┬───┬─────────────┬────────────────┬────┬────┬───────────┬────┬───────┬────┬──────────────────────────────────────┐
│42│1:8│9 Kings│7th│War and Peace│Home for a Bunny│Mark│John│Revelations│Luke│Matthew│Maus│Reading Rainbow: The Best Unicorn Ever│
└──┴───┴───────┴───┴─────────────┴────────────────┴────┴────┴───────────┴────┴───────┴────┴──────────────────────────────────────┘

Spiegazione:

  • ⎕ML←3: impostato ⎕MLsu 3(per )
  • ⍵[⍋{... }¨⍵]: ordina l'input in base ai valori restituiti dalla funzione interna
    • ↑¨⍵⊂⍨⍵≠' ': ottiene il primo carattere di ogni parola
    • 2='R'+.=: vedi se due di questi sono 'R'.
    • :!99: in tal caso, restituisci 99! (≈ 9.3 × 10 155 ). Questo non è del tutto infinito, ma lo farà: un titolo non può mai avere un punteggio più di 38 volte la sua lunghezza (ZZZZ ...), quindi fintanto che nessun singolo titolo è più grande di circa 2 × 10 130 yottabyte, esso è garantito che questi saranno alla fine.
    • : altrimenti:
    • (... )÷⍴⍵: dividi il punteggio per la lunghezza di dopo averlo calcolato:
      • G←(⊂⎕A),(⎕UCS 96+⍳26): memorizza Gle lettere maiuscole e minuscole
      • (⎕UCS 32+⍳94)~'`',⎕D,∊G: i caratteri ASCII stampabili, ad eccezione di lettere, cifre, spazi e '`', che sono i caratteri per i quali viene sottratto un punto. (Questo è più breve di scriverli tutti, perché Gverrà utilizzato in seguito.)
      • +/⍵∊: conta la quantità di questi caratteri in
      • -: sottrai questo da:
      • +/∊1.5 1×(⍳×∊⍨)∘⍵¨G: la somma di 1,5 × i punteggi per le maiuscole e 1 × i punteggi per le lettere minuscole.
    • -⍨: successivamente, sottrarre il totale dei numeri in :
      • ⍵⊂⍨⍵∊⎕D: trova i gruppi di cifre in
      • '0',: aggiungi '0', per evitare che l'elenco sia vuoto
      • ⍎¨: valuta ogni stringa
      • +/: trova la somma

Invece di !99te potresti usare⌊/⍬
Adám

1
Adoro guardare il codice lungo in APL. Mi fa sentire che il mondo è molto più grande di me. E mi piacciono i simboli.
Conor O'Brien,

2

Lua 5.3, 366 364 byte

r={}for i,s in ipairs(arg)do n=0 s:gsub("%l",function(a)n=n+(a:byte()-96)end):gsub("%u",function(a)n=n+(a:byte()-64)*1.5 end):gsub("%p",function(a)n=n-1 end):gsub("^R?.- R.- ?R?",function()n=math.huge end)m=n/utf8.len(s)s:gsub("%d+",function(a)m=m-a end)table.insert(r,{s=s,n=m})end table.sort(r,function(a,b)return a.n<b.n end)for i,v in ipairs(r)do print(v.s)end

Questo codice funziona solo in Lua 5.3 perché deve gestire i caratteri Unicode. Se non ti interessa Unicode, sostituisci "utf8" con "stringa" e funzionerà perfettamente con Lua 5.2 o 5.1.

Prende i suoi input dagli argomenti della riga di comando, quindi eseguilo dalla riga di comando o metti questo codice sopra la mia risposta:

arg = {"Title 1", "Title 2", "Title 3"}

Non ho Lua 5.3 sulla mia macchina, ma ho seguito il suo suggerimento di scambio utf8con l'Ideone e non ho ricevuto in uscita. string
AdmBorkBork,

@TimmyD guarda la mia modifica
Trebuchette,

Buono. Sugo. Ed (arg)è seduto lì a fissarmi in faccia. A quanto pare questa domanda mi ha spezzato il cervello. Prendi un +1.
AdmBorkBork,

Con MoonScript, questo è 266 byte: pastebin.com/wr4qVs5h .
Kirbyfan64sos,

2

Mathematica, 253 216 byte (214 caratteri)

r=RegularExpression;c=ToCharacterCode;f=SortBy[Tr@Flatten@Reap[StringCases[#,
{r@"(\\bR.*)+"->∞,r@"\\d+":>0Sow@-FromDigits@"$0",r@"[a-z]":>c@"$0"-96,
r@"[A-Z]":>1.5c@"$0"-96,r@"[!-/:-@[-_{-~]"->-1}]/StringLength@#]&]

Chiamare la funzione come f[{"42", "9 Kings", "1:8", "7th"}] ; restituirà un elenco ordinato degli input.

Appena fatto! La corrispondenza del modello di Mathematica non è così concisa quando sono coinvolte le stringhe, e mi vengono solo uccisi da quei nomi lunghi. I due byte extra sono perInfinity carattere Unicode.

(Fammi sapere se sono caduto a rischio di eventuali scappatoie standard.)

Aggiornare

Osservando un po 'più da vicino la risposta di edc65, sembra che l'OP accetterà una funzione che ordina un elenco di stringhe. Con questo in mente possiamo usare la forma al curry SortBy(che Mathematica chiama la "forma dell'operatore"); con un argomento (la funzione applicata agli elementi della lista per determinare il loro ordine) si comporta come una funzione che accetta un argomento, restituendo la forma ordinata dell'input; cioè SortBy[list, f]equivale a (SortBy[f])[list].

Ungolfed

Function[{titles},
  SortBy[titles, Function[{str}, (* sort by function value *)
    Total[Flatten[Reap[ (* total up all the parts *)
      StringCases[str, {
        RegularExpression["(\\bR.*){2}"] -> Infinity
          (* matches R at the start of a word twice, adds infinity to the total *),
        RegularExpression["\\d+"] :> 0 * Sow[-FromDigits["$0"]]
          (* matches a number, Sows it for Reap to collect, then multiplies by zero
                                                          to not affect the average *),
        RegularExpression["[a-z]"] :> ToCharacterCode["$0"] - 96
          (* matches a lowercase letter and returns its value *),
        RegularExpression["[A-Z]"] :> 1.5 ToCharacterCode["$0"] - 96
          (* matches an uppercase letter and returns 1.5 its value *),
        RegularExpression["[!-/:-@[-_{-~]"] -> -1
          (* matches a 'grandiose' symbol and returns -1 *)
      }] / StringLength[#] (* averages character values *)
    ]]]
  ]]
]

1
Bella risposta, e ottieni un cookie Internet per usare letteralmente "infinito" nei tuoi calcoli ;-).
AdmBorkBork,

@TimmyD La bellezza dell'elaborazione simbolica della matematica =)
2012rcampion

Probabilmente intendi 214 caratteri, 216 byte. Ben fatto, ho provato a competere ma assolutamente no
edc65

2

JavaScript (ES6), 210 218 251

Come una funzione con un argomento array, restituito ordinato.

f=L=>(S=s=>([...s].map(c=>t-=(a=s.charCodeAt(l++))>32&a<48|a>57&a<65|a>90&a<96|a>122&a<127?1:a>64&a<123?96-(a<96?a*1.5:a):0,l=t=0),s.split(/\D/).map(n=>t-=n,t/=l),t/!s.split(/\bR/)[2]),L.sort((a,b)=>S(a)-S(b)))

//TEST

test1=['War and Peace','Reading Rainbow: The Best Unicorn Ever','Maus','Home for a Bunny']
test2=['Matthew','Mark','Luke','John','Revelations']
test3=['42','9 Kings','1:8','7th']

;O.innerHTML=f(test1)+'\n\n'+f(test2)+'\n\n'+f(test3);

// The comparing function used to sort, more readable

Sort=s=>(
  t = 0, // running total
  l = 0, // to calc the string length avoiding the '.length' property
  [...s].map(c=>{
    a=s.charCodeAt(l++);
    t-=a>32&a<48|a>57&a<65|a>90&a<96|a>122&a<127
      ? 1 // symbols (ASCII char except space, alphanumeric and backtick)
      : a>64&a<123 
        ? 96-(a<96?a*1.5:a) // alphabetic both upcase and lowcase, and backtick
        // lowcase: 96-a, upcase (64-a)*1.5=>96-a*1.5, backtick is 96 and 96-96 == 0
        : 0 // else space, non ASCII, and numeric : 0
  }),
  t = t/l, // average
  s.split(/\D/).map(n=>t-=n), // sub number values
  f = s.split(/\bR/)[2], // split at words starting with R, if less then 2 f is undefined
  t/!f // dividing by not f I can get the infinity I need
)
<pre id=O></pre>


Ben fatto. Per riferimento a chiunque leggesse questa risposta, ho dovuto passare O.innerHTMLa this.InnerHTMLnella console di Firefox.
AdmBorkBork,

1

C #, 352 349 byte

A causa della magia di Linq:

class A{static void Main(string[]a){foreach(var x in a.OrderBy(b=>{var s="0";int j=0;return Regex.Split(b,@"[^\w]+").Count(l=>l[0]=='R')==2?(1/0d):b.Aggregate(0d,(d,e)=>{if(e>47&e<58){s+=e;return d;}d+=(e>64&e<91)?(e-64)*1.5:(e>96&e<123)?e-96:e>32&e<127&e!=96?-1:0;j+=int.Parse(s);s="0";return d;})/b.Length-j-int.Parse(s);}))Console.WriteLine(x);}}

Avrebbe potuto salvare altri 6 byte se il backtick fosse incluso nell'elenco di punteggiatura!

class A
{
    static void Main(string[] a)
    {
        foreach (var x in a.OrderBy(b =>
            {
                var s = "0";
                int j = 0;
                return Regex.Split(b, @"[^\w]+").Count(l => l[0] == 'R') == 2
                    ? (1 / 0d)
                        : b.Aggregate(0d, (d, e) =>
                        {
                            if (e > 47 & e < 58) { s += e; return d; }
                            d += (e > 64 & e < 91) ? (e - 64) * 1.5 : (e > 96 & e < 123) ? e - 96 : e > 32 & e < 127 & e != 96 ? -1 : 0;
                            j += int.Parse(s);
                            s = "0";
                            return d;
                        }) / b.Length - j - int.Parse(s);
            }))
            Console.WriteLine(x);
    }

}

1

Vai, 755 byte

package main
import("os"
"fmt"
"math"
"bufio"
"regexp"
"sort"
"strconv")
type F float64
type T []F
func(t T)Swap(i,j int){t[i],t[j],S[i],S[j]=t[j],t[i],S[j],S[i]}
func(t T)Len()int{return len(t)}
func(t T)Less(i,j int)bool{return t[i]<t[j]}
var S []string
func main(){var t T
for{b:=bufio.NewReader(os.Stdin)
w,_,_:=b.ReadLine()
if len(w)==0{break}
u:=string(w)
var v F
for _,c:=range u{if 96<c&&c<123{v+=F(c)-F(96)}else
if 64<c&&c<91{v+=(F(c)-64)*1.5}else
if (48>c&&c>32)||(c>57&&c<127){v-=1}}
a:=v/F(len(w))
r,_:=regexp.Compile("[0-9]+")
n:=r.FindAllString(string(w),-1)
for _,x:=range n{y,_:=strconv.Atoi(x);a-=F(y)}
if m,_:=regexp.Match("((^| )R.*){2}",w);m{a=F(math.Inf(1))}
S=append(S,u)
t=append(t,a)}
sort.Sort(t)
for _,o:=range S{fmt.Println(o)}}

La versione formattata:

package main

import (
    "bufio"
    "fmt"
    "math"
    "os"
    "regexp"
    "sort"
    "strconv"
)

type F float64
type T []F

func (t T) Swap(i, j int)      { t[i], t[j], S[i], S[j] = t[j], t[i], S[j], S[i] }
func (t T) Len() int           { return len(t) }
func (t T) Less(i, j int) bool { return t[i] < t[j] }

var S []string

func main() {
    var t T
    for {
        b := bufio.NewReader(os.Stdin)
        w, _, _ := b.ReadLine()
        if len(w) == 0 {
            break
        }
        u := string(w)
        var v F
        for _, c := range u {
            if 96 < c && c < 123 {
                v += F(c) - F(96)
            } else if 64 < c && c < 91 {
                v += (F(c) - 64) * 1.5
            } else if (48 > c && c > 32) || (c > 57 && c < 127) {
                v -= 1
            }
        }
        a := v / F(len(w))
        r, _ := regexp.Compile("[0-9]+")
        n := r.FindAllString(string(w), -1)
        for _, x := range n {
            y, _ := strconv.Atoi(x)
            a -= F(y)
        }
        if m, _ := regexp.Match("((^| )R.*){2}", w); m {
            a = F(math.Inf(1))
        }
        S = append(S, u)
        t = append(t, a)
    }
    sort.Sort(t)
    for _, o := range S {
        fmt.Println(o)
    }
}

L'implementazione di un'interfaccia di ordinamento personalizzata l'ha resa più lunga del previsto. Il programma legge da STDIN fino a quando non viene immessa la fine dell'ingresso o una riga vuota.


1

PHP, 362 367 byte

<?for(;$w=fgets(STDIN);$S[]=$w){for($l=$i=mb_strlen($w);$i--;){$c=array_sum(unpack("C*",mb_substr($w,$i,1)));96<$c&&$c<123 and $v+=$c-96 or 64<$c&&$c<91 and $v+=1.5*$c-96 or 48<$c&&$c>32||$c>57&&$c<127 and $v-=1;}$v/=$l;preg_match_all("/\d+/",$w,$m);$v-=array_sum($m[0]);preg_match("/((^| )R.*){2}/",$w)&&$v=INF;$t[]=$v;}array_multisort($t,$S);echo join("
",$S);

Versione formattata:

<?php
for (; $w = fgets(STDIN); $S[] = $w) {
    for ($l = $i = mb_strlen($w); $i--;) {
        $c = array_sum(unpack("C*", mb_substr($w, $i, 1)));
        96 < $c && $c < 123 and $v += $c - 96
        or 64 < $c && $c < 91 and $v += 1.5 * $c - 96
        or 48 < $c && $c > 32 || $c > 57 && $c < 127 and $v -= 1;
    }
    $v /= $l;
    preg_match_all("/\d+/", $w, $m);
    $v -= array_sum($m[0]);
    preg_match("/((^| )R.*){2}/", $w) && $v = INF;
    $t[] = $v;
}
array_multisort($t, $S);
echo join("
", $S); 

Linee interessanti:

$c = array_sum(unpack("C*", mb_substr($w, $i, 1)));

Converte un singolo carattere UTF-8 nei suoi valori byte e li somma, in modo da ottenere il valore reale per i caratteri ASCII e un valore superiore a 127 per i caratteri multibyte.

96 < $c && $c < 123 and $v += $c - 96
or 64 < $c && $c < 91 and $v += 1.5 * $c - 96
or 48 < $c && $c > 32 || $c > 57 && $c < 127 and $v -= 1;

Utilizza la precedenza bassa dell'operatore di ande orper assegnare il valore del carattere in una singola istruzione senza if.


1

Perl 5 , 190 byte

sub p{$_=pop;chomp;$c=-y/A-Za-z0-9 \\`//c;map$c+=(32&ord$_?1:1.5)*(31&ord),/[a-z]/gi;$c/=length;map$c-=$_,/\d+/g;$c}say(sort{$y=$b=~/\bR.*\bR/;($x=$a=~/\bR.*\bR/)||$y?$x-$y:(p($a)<=>p$b)}<>)

Provalo online!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.