Niesamowity system sortowania szalonego bibliotekarza

21

Powrót do sezonu szkolnego! W przypadku pracy w niepełnym wymiarze godzin pomagasz w szkolnej bibliotece. Problem polega na tym, że główny bibliotekarz nigdy nie słyszał słowa „Dewey Decimal”, nie mówiąc już o wdrożeniu tego systemu. Zamiast tego używany system sortowania urósł „organicznie”, ponieważ biblioteka się rozszerzyła ...

Aby zachować zdrowie psychiczne, postanowiłeś napisać program, który pomoże ci sortować książki po ich zwróceniu, bo biada ci, jeśli źle posortujesz książki. (Główny bibliotekarz jest BARDZO surowy).

Wejście wyjście

  • Wprowadzana będzie lista (hipotetycznych) tytułów książek, po jednym w wierszu, z STDIN / odpowiednika językowego.
  • Jednocześnie możesz założyć, że wkładanych jest nie więcej niż 100 książek (możesz jednocześnie nosić tylko tyle książek w bibliotece).
  • Książki mogą zawierać wiele słów w swoich tytułach, które mogą być oddzielone spacjami lub innymi znakami interpunkcyjnymi (np. Dwukropek :, myślnik -itp.).
  • Dla ułatwienia obliczeń załóż, że wszystkie tytuły to UTF-8.

Dane wyjściowe to te same tytuły, posortowane zgodnie z poniższymi zasadami, ponownie po jednym w wierszu, do STDOUT / odpowiednika językowego.

Zasady sortowania

Książki są sortowane numerycznie na podstawie ich średniej wartości znaków (tj. Skumulowanej wartości znaku podzielonej liczby znaków w tytule książki), zliczonej według następujących reguł:

  • Wszystkie znaki liczą się do określenia liczby znaków w tytule.
  • Małe litery są liczone według ich pozycji w alfabecie. (a = 1, b = 2, ... z = 26)
  • Jeśli tytuł zawiera wielkie litery, liczą one 1,5 wartości małej litery (A = 1,5, B = 3, ... Z = 39). („Ważne są wielkie litery!”, Mówi bibliotekarz).
  • Każdy znak interpunkcyjny / symbol na tej liście !@#$%^&*()-=_+[]\{}|;':",./<>?~liczy -1 od wartości skumulowanej przed uśrednieniem. („Wielkie tytuły nie są!”)
  • Jeśli tytuł zawiera liczbę zapisaną cyframi arabskimi , liczba ta jest odejmowana od średniej wartości przed sortowaniem. Wiele kolejnych cyfr jest traktowanych jako jedna liczba (np. 42Odejmuje 42, a nie odejmuje 4, a następnie odejmuje 2). Poszczególne cyfry nie liczą się do wartości skumulowanej (tj. Każda cyfra odpowiada 0), ale DO liczą się liczby znaków. Należy pamiętać, że może to spowodować ujemną wartość i powinno być odpowiednio traktowane. (Plotka głosi, że bibliotekarz zakochał się w instruktorze matematyki od kilku lat).
  • Jeśli tytuł zawiera dwa osobne słowa rozpoczynające się od R, książka otrzymuje wynik „nieskończoności” i jest zrzucana na stos w rogu (tj. Losowo ułożona na końcu listy). (Bibliotekarz został kiedyś porzucony przez osobę z tymi inicjałami, a przynajmniej tak słyszeliście).
  • Spacje nie liczą się do skumulowanej wartości znaku (tj. Przyczyniają się do 0), ale DO przyczyniają się do liczby znaków w tytule.
  • Znaki, które nie pasują do powyższych zasad (np. A ÿ), nie liczą się do skumulowanej wartości postaci (tj. Mają wartość 0), ale DOKŁADNIE przyczyniają się do liczby znaków w tytule.
  • Na przykład hipotetyczna książka ÿÿÿÿÿmiałaby „partyturę” (0+0+0+0+0) / 5 = 0, ale hipotetyczna książka ÿÿyÿÿmiałaby „partyturę” (0+0+25+0+0) / 5 = 5.
  • Dwie książki, które tak samo „zdobywają punkty”, mogą zostać wydrukowane w wybranym porządku. (W każdym razie są na tej samej półce)

Przykład danych wejściowych 1

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

Przykład Wyjście 1 (z „wynikami” w nawiasach, aby pokazać uzasadnienie - nie trzeba ich drukować)

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

Przykład danych wejściowych 2

Matthew
Mark
Luke
John
Revelations

Przykład Wyjście 2 (z „wynikami” w nawiasach, aby pokazać uzasadnienie - nie trzeba ich drukować)

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

Przykład danych wejściowych 3

42
9 Kings
1:8
7th

Przykład Wyjście 3 (z „wynikami” w nawiasach, aby pokazać uzasadnienie - nie trzeba ich drukować)

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

Inne ograniczenia

  • To jest Code-Golf, ponieważ musisz trzymać program w tajemnicy przed wiecznie obserwującymi oczami bibliotekarza, a im mniejszy program, tym łatwiej jest go ukryć.
  • Obowiązują standardowe ograniczenia dotyczące luk
  • Nie pozwól, aby bibliotekarz złapał cię na luzie, spędzając cały swój czas na PPCG.
AdmBorkBork
źródło
Co jeśli dwie książki zdobędą dokładnie to samo. tzn. mam Reading Rainbow i Ruby Rails
Kishan Kumar,
@KishanKumar W tym konkretnym przypadku „losowo ułożone na końcu listy”, ponieważ oba mają podwójne R. Innymi słowy, wybierz. W ogólnym przypadku, jeśli dwa słowa mają takie same wyniki, mogą pojawić się w dowolnej kolejności względem siebie. Dodam kulę, aby to wyjaśnić.
AdmBorkBork
7
Potrzebujesz słowa A, aby twój system miał nazwę akronimu. Polecam niesamowity system sortowania Crazy Librarian: D
Geobits
3
@Geobits Czy masz klasę?
AdmBorkBork
Liczby to tylko liczby dziesiętne? Co jeśli jest ich kilka, czy wszystkie są odejmowane osobno?
Paŭlo Ebermann

Odpowiedzi:

5

APL (132)

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

Ponieważ wszyscy robią to samo, również ta funkcja pobiera tablicę tytułów i zwraca ją posortowaną, np .:

      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│
└──┴───┴───────┴───┴─────────────┴────────────────┴────┴────┴───────────┴────┴───────┴────┴──────────────────────────────────────┘

Wyjaśnienie:

  • ⎕ML←3: ustaw ⎕MLna 3(dla )
  • ⍵[⍋{... }¨⍵]: sortuj dane wejściowe według wartości zwróconych z funkcji wewnętrznej
    • ↑¨⍵⊂⍨⍵≠' ': uzyskaj pierwszy znak każdego słowa
    • 2='R'+.=: sprawdź, czy dwa z nich są 'R'.
    • :!99: jeśli tak, zwróć 99! (≈ 9,3 × 10 155 ). To nie jest nieskończona nieskończoność, ale tak się stanie: tytuł nigdy nie będzie miał wyniku większego niż 38-krotność jego długości (ZZZZ ...), więc dopóki żaden tytuł nie jest większy niż około 2 × 10 130 yottabajtów, gwarantuje się, że będą na końcu.
    • : Inaczej:
    • (... )÷⍴⍵: podziel wynik przez długość po obliczeniu:
      • G←(⊂⎕A),(⎕UCS 96+⍳26): przechowuj Gwielkie i małe litery
      • (⎕UCS 32+⍳94)~'`',⎕D,∊G: drukowalne znaki ASCII, z wyjątkiem liter, cyfr, spacji i '`', które są znakami, za które odejmuje się punkt. (Jest to krótsze niż wypisanie ich wszystkich, ponieważ Gjest używane później).
      • +/⍵∊: policz liczbę tych znaków
      • -: odejmij to od:
      • +/∊1.5 1×(⍳×∊⍨)∘⍵¨G: suma 1,5 × wyników dla wielkich liter i 1 × wyników dla małych liter.
    • -⍨: następnie odejmij sumę liczb w :
      • ⍵⊂⍨⍵∊⎕D: znajdź grupy cyfr w
      • '0',: dodaj '0', aby lista nie była pusta
      • ⍎¨: oceń każdy ciąg
      • +/: znajdź sumę
marinus
źródło
Zamiast !99ciebie możesz skorzystać⌊/⍬
Adám
1
Uwielbiam patrzeć na długi kod w APL. Sprawia, że ​​czuję, że świat jest o wiele większy niż ja. Lubię symbole.
Conor O'Brien,
2

Lua 5.3, 366 364 bajtów

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

Ten kod działa tylko w Lua 5.3, ponieważ musi obsługiwać znaki Unicode. Jeśli nie zależy ci na Unicode, zamień „utf8” na „string” i będzie działać poprawnie z Lua 5.2 lub 5.1.

Bierze dane wejściowe z argumentów wiersza poleceń, więc albo uruchom go z wiersza poleceń, albo umieść ten kod nad moją odpowiedzią:

arg = {"Title 1", "Title 2", "Title 3"}
Trebuchette
źródło
Nie mam Lua 5.3 na moim komputerze, ale następnie swoją propozycję, aby zamienić utf8z stringdnia Ideone i dostał żadnego wyjścia.
AdmBorkBork
@ TimmyD zobacz moją edycję
Trebuchette
Dobry. Sos. I (arg)siedzi tam, wpatrując się we mnie w twarz. To pytanie najwyraźniej usmażyło mi mózg. Masz +1.
AdmBorkBork
W przypadku MoonScript jest to 266 bajtów: pastebin.com/wr4qVs5h .
kirbyfan64sos
2

Mathematica, 253 216 bajtów (214 znaków)

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@#]&]

Wywołaj funkcję jak f[{"42", "9 Kings", "1:8", "7th"}]; zwróci posortowaną listę danych wejściowych.

Ledwo się udało! Dopasowywanie wzorców Mathematiki nie jest tak zwięzłe, gdy zaangażowane są łańcuchy, i po prostu zabijają mnie te długie nazwy. Dodatkowe dwa bajty dotyczą Infinityznaku Unicode.

(Daj mi znać, jeśli popełniłem jakieś standardowe luki).

Aktualizacja

Przyglądając się nieco bliżej odpowiedzi edc65, wygląda na to, że OP zaakceptuje funkcję sortującą listę ciągów. Mając to na uwadze, możemy użyć formy curry SortBy(którą Mathematica nazywa „formą operatora”); z jednym argumentem (funkcja zastosowana do elementów listy w celu ustalenia ich kolejności) zachowuje się jak funkcja, która przyjmuje jeden argument, zwracając posortowaną formę danych wejściowych; to znaczy SortBy[list, f]jest równoważne z (SortBy[f])[list].

Nie golfił

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 *)
    ]]]
  ]]
]
2012 rcampion
źródło
1
Fajna odpowiedź, a dostajesz plik cookie do Internetu za dosłowne użycie „nieskończoności” w swoich obliczeniach ;-).
AdmBorkBork,
@TimmyD Piękno symbolicznego przetwarzania matematyki =)
2012rcampion
Prawdopodobnie masz na myśli 214 znaków, 216 bajtów. Dobra robota, próbowałem konkurować, ale nie ma mowy
edc65
2

JavaScript (ES6), 210 218 251

Jako funkcja z argumentem tablicowym zwróciła posortowane.

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>

edc65
źródło
Ładnie wykonane. Dla porównania nikomu przeczytaniu tej odpowiedzi, musiałem zmienić O.innerHTMLsię this.InnerHTMLw konsoli Firefoksa.
AdmBorkBork,
1

C #, 352 349 bajtów

Ze względu na magię 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);}}

Mógłbym zapisać kolejne 6 bajtów, gdyby backtick znalazł się na liście interpunkcyjnej!

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);
    }

}
Yitz
źródło
1

Idź, 755 bajtów

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)}}

Sformatowana wersja:

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)
    }
}

Wdrożenie niestandardowego interfejsu sortowania sprawiło, że był on dłuższy niż oczekiwano. Program odczytuje ze STDIN do końca wprowadzania pustej linii.

Fabian Schmengler
źródło
1

PHP, 362 367 Bajtów

<?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);

Wersja sformatowana:

<?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); 

Ciekawe linie:

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

Konwertuje pojedynczy znak UTF-8 na jego wartości bajtowe i sumuje je, dzięki czemu otrzymujemy rzeczywistą wartość znaków ASCII i wartość wyższą niż 127 dla znaków wielobajtowych.

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;

Wykorzystuje niski priorytet operatora andi orprzypisuje wartość znaku w pojedynczej instrukcji bez if.

Fabian Schmengler
źródło
1

Perl 5 , 190 bajtów

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)}<>)

Wypróbuj online!

Xcali
źródło