Sistem Penyortiran Menakjubkan Pustakawan Gila

21

Ini kembali ke musim sekolah! Jadi untuk pekerjaan paruh waktu, Anda membantu di perpustakaan sekolah. Masalahnya adalah, kepala perpustakaan bahkan belum pernah mendengar kata-kata "Dewey Decimal," apalagi menerapkan sistem itu. Sebagai gantinya, sistem penyortiran yang digunakan telah tumbuh "organik" karena perpustakaan telah berkembang ...

Dalam upaya menjaga kewarasan Anda, Anda telah memilih untuk menulis sebuah program untuk membantu Anda menyortir buku ketika dikembalikan, karena celakalah Anda jika Anda salah mengurutkan buku. (Pustakawan kepala SANGAT ketat.)

Input output

  • Masukan akan berupa daftar judul buku (hipotetis), satu judul per baris, dari STDIN / padanan bahasa.
  • Anda dapat mengasumsikan tidak lebih dari 100 input buku sekaligus (Anda hanya dapat membawa begitu banyak perpustakaan sekaligus).
  • Buku dapat memiliki beberapa kata dalam judulnya, dan kata-kata ini dapat dipisahkan dengan spasi atau tanda baca lainnya (misalnya, tanda titik dua :, tanda hubung -, dll.).
  • Untuk kemudahan perhitungan, anggap semua judul adalah UTF-8.

Output adalah judul yang sama, disortir menurut aturan di bawah ini, sekali lagi satu per baris, ke STDOUT / bahasa yang setara.

Aturan Penyortiran

Buku diurutkan secara numerik berdasarkan nilai karakter rata-rata mereka (yaitu, nilai karakter kumulatif membagi jumlah karakter dalam judul buku), dihitung dengan aturan berikut:

  • Semua karakter dihitung untuk menentukan jumlah karakter dalam suatu judul.
  • Huruf kecil dihitung berdasarkan posisinya dalam alfabet. (a = 1, b = 2, ... z = 26)
  • Jika judul berisi huruf kapital, yang dihitung sebesar 1,5 nilai huruf kecilnya (A = 1,5, B = 3, ... Z = 39). ("Huruf kapital penting!" Kata pustakawan itu.)
  • Setiap tanda baca / simbol dalam daftar ini !@#$%^&*()-=_+[]\{}|;':",./<>?~dihitung -1 dari nilai kumulatif sebelum rata-rata. ("Gelar muluk tidak!")
  • Jika judul berisi angka, ditulis dalam angka Arab , angka itu dikurangi dari nilai rata-rata sebelum disortir. Beberapa digit berurutan diperlakukan sebagai satu angka (misalnya, 42akan mengurangi 42, tidak mengurangi 4 dan kemudian mengurangi 2). Digit individu tidak dihitung untuk nilai kumulatif (yaitu, setiap digit berkontribusi 0), tetapi DO menghitung jumlah karakter. Perhatikan bahwa ini dapat menghasilkan nilai negatif dan harus diperlakukan dengan tepat. (Rumor mengatakan, pustakawan naksir instruktur matematika selama beberapa tahun, sekarang.)
  • Jika judul berisi dua kata terpisah yang dimulai dengan R, buku mendapat skor "tak terbatas" dan dibuang ke tumpukan di sudut (yaitu, diatur secara acak di akhir daftar). (Pustakawan itu pernah dibuang oleh seseorang dengan inisial itu, atau begitulah yang Anda dengar.)
  • Spasi tidak dihitung untuk nilai karakter kumulatif (yaitu, mereka berkontribusi 0), tetapi DO berkontribusi pada jumlah karakter dalam judul.
  • Karakter yang tidak sesuai dengan aturan di atas (misalnya, a ÿ) tidak dihitung untuk nilai karakter kumulatif (yaitu, mereka berkontribusi 0), tetapi DO berkontribusi pada jumlah karakter dalam judul.
  • Sebagai contoh, sebuah buku hipotetis ÿÿÿÿÿakan memiliki "skor" (0+0+0+0+0) / 5 = 0, tetapi sebuah buku hipotetis ÿÿyÿÿakan memiliki "skor" (0+0+25+0+0) / 5 = 5.
  • Dua buku yang kebetulan "mencetak" yang sama dapat menjadi Output dalam pilihan pesanan Anda. (Lagi pula, mereka berada di rak yang sama)

Contoh Input 1

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

Contoh Output 1 (dengan "skor" dalam tanda kurung untuk menunjukkan alasan - Anda tidak perlu mencetaknya)

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

Contoh Input 2

Matthew
Mark
Luke
John
Revelations

Contoh Output 2 (dengan "skor" dalam tanda kurung untuk menunjukkan alasan - Anda tidak perlu mencetaknya)

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

Contoh Input 3

42
9 Kings
1:8
7th

Contoh Output 3 (dengan "skor" dalam tanda kurung untuk menunjukkan alasan - Anda tidak perlu mencetaknya)

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

Pembatasan lainnya

  • Ini adalah Code-Golf, karena Anda harus menjaga rahasia program dari mata pustakawan yang selalu menonton, dan semakin kecil programnya, semakin mudah disembunyikan.
  • Batasan celah standar berlaku
  • Jangan biarkan pustakawan menangkap Anda malas dengan menghabiskan seluruh waktu Anda di PPCG.
AdmBorkBork
sumber
Bagaimana jika dua buku memiliki skor yang persis sama. yaitu saya Have Reading Rainbow dan Ruby Rails
Kishan Kumar
@KishanKumar Dalam contoh khusus itu, "diatur secara acak di akhir daftar" karena keduanya sama-sama R-ganda. Dengan kata lain, pilihlah. Dalam kasus umum, jika dua kata memiliki skor yang sama, mereka dapat muncul dalam urutan apa pun relatif satu sama lain. Saya akan menambahkan peluru untuk mengklarifikasi itu.
AdmBorkBork
7
Anda memerlukan kata A sehingga sistem Anda memiliki nama akronim. Saya merekomendasikan Amazing Sorting System Crazy Librarian: D
Geobits
3
@Geobits Anda punya CLASS?
AdmBorkBork
Angka hanyalah angka desimal? Bagaimana jika ada beberapa, apakah semuanya dikurangi secara terpisah?
Paŭlo Ebermann

Jawaban:

5

APL (132)

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

Karena semua orang melakukan hal yang sama, ini juga adalah fungsi yang mengambil array judul dan mengembalikannya diurutkan, misalnya:

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

Penjelasan:

  • ⎕ML←3: setel ⎕MLke 3(untuk )
  • ⍵[⍋{... }¨⍵]: urutkan input berdasarkan nilai yang dikembalikan dari fungsi dalam
    • ↑¨⍵⊂⍨⍵≠' ': dapatkan karakter pertama dari setiap kata
    • 2='R'+.=: lihat apakah dua di antaranya 'R'.
    • :!99: jika demikian, kembalikan 99! (≈ 9.3 × 10 155 ). Ini bukan tak terhingga, tetapi ia akan berhasil: sebuah judul tidak akan pernah bisa memiliki skor lebih dari 38 kali panjangnya (ZZZZ ...), jadi selama tidak ada judul tunggal yang lebih besar dari sekitar 2 × 10 130 yottabytes, itu dijamin bahwa ini akan menjadi pada akhirnya.
    • : jika tidak:
    • (... )÷⍴⍵: bagi skor dengan panjang setelah menghitungnya:
      • G←(⊂⎕A),(⎕UCS 96+⍳26): simpan dalam Ghuruf besar dan kecil
      • (⎕UCS 32+⍳94)~'`',⎕D,∊G: karakter ASCII yang dapat dicetak, kecuali huruf, angka, spasi dan '`', yang merupakan karakter yang titiknya dikurangkan. (Ini lebih pendek daripada menulis semuanya, karena Gdigunakan nanti.)
      • +/⍵∊: hitung jumlah karakter ini di
      • -: kurangi ini dari:
      • +/∊1.5 1×(⍳×∊⍨)∘⍵¨G: jumlah 1,5 × skor untuk ibukota, dan 1 × skor untuk huruf kecil.
    • -⍨: setelah itu, kurangi total angka dalam :
      • ⍵⊂⍨⍵∊⎕D: temukan grup digit di
      • '0',: add '0', untuk mencegah daftar kosong
      • ⍎¨: mengevaluasi setiap string
      • +/: temukan jumlahnya
marinus
sumber
Alih-alih !99Anda bisa menggunakan⌊/⍬
Adám
1
Saya suka melihat kode panjang di APL. Itu membuat saya merasa dunia jauh lebih besar dari saya. Dan saya suka simbol.
Conor O'Brien
2

Lua 5.3, 366 364 Bytes

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

Kode ini hanya berfungsi di Lua 5.3 karena harus berurusan dengan karakter Unicode. Jika Anda tidak peduli tentang Unicode, maka ganti "utf8" dengan "string" dan itu akan berfungsi dengan baik dengan Lua 5.2 atau 5.1.

Dibutuhkan input dari argumen baris perintah, jadi jalankan dari baris perintah atau letakkan kode ini di atas jawaban saya:

arg = {"Title 1", "Title 2", "Title 3"}
Trebuchette
sumber
Saya tidak memiliki Lua 5.3 di komputer saya, tetapi saya mengikuti saran Anda untuk bertukar utf8dengan stringdi Ideone dan tidak mendapat hasil.
AdmBorkBork
@TimmyD lihat edit saya
Trebuchette
Baik. Saus. Dan (arg)sedang duduk di sana menatap wajahku. Pertanyaan ini rupanya menggoreng otak saya. Punya +1.
AdmBorkBork
Dengan MoonScript, ini adalah 266 byte: pastebin.com/wr4qVs5h .
kirbyfan64sos
2

Mathematica, 253 216 byte (214 karakter)

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

Panggil fungsi seperti f[{"42", "9 Kings", "1:8", "7th"}]; itu akan mengembalikan daftar input yang diurutkan.

Baru saja berhasil! Pencocokan pola Mathematica tidak sesingkat ketika string terlibat, dan saya baru saja terbunuh oleh nama-nama panjang itu. Dua byte tambahan adalah untuk Infinitykarakter unicode.

(Beri tahu saya jika saya telah berselisih dengan Celah Standar.)

Memperbarui

Melihat sedikit lebih dekat pada jawaban edc65, sepertinya OP akan menerima fungsi yang mengurutkan daftar string. Dengan mengingat hal itu, kita dapat menggunakan bentuk kari SortBy(yang Mathematica menyebutnya "bentuk operator"); dengan satu argumen (fungsi diterapkan ke elemen daftar untuk menentukan urutannya) berperilaku seperti fungsi yang mengambil satu argumen, mengembalikan bentuk input yang diurutkan; yaitu SortBy[list, f]setara dengan (SortBy[f])[list].

Tidak disatukan

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 Arcampion
sumber
1
Jawaban yang bagus, dan Anda mendapatkan Cookie Internet untuk benar-benar menggunakan "tak terbatas" dalam perhitungan Anda ;-).
AdmBorkBork
@TimmyD Keindahan pemrosesan matematika simbolik =)
2012rcampion
Mungkin maksud Anda 214 karakter, 216 byte. Bagus, saya mencoba untuk bersaing tetapi tidak ada cara
edc65
2

JavaScript (ES6), 210 218 251

Sebagai fungsi dengan argumen array, kembali diurutkan.

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
sumber
Bagus sekali. Untuk referensi siapa pun yang membaca jawaban ini, saya harus beralih O.innerHTMLke this.InnerHTMLdi konsol Firefox.
AdmBorkBork
1

C #, 352 349 Bytes

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

Bisa menyimpan 6 byte lagi jika backtick akan dimasukkan dalam daftar tanda baca!

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
sumber
1

Pergi, 755 Bytes

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

Versi yang diformat:

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

Menerapkan antarmuka pengurutan khusus membuatnya lebih lama dari yang diharapkan. Program membaca dari STDIN sampai akhir input atau baris kosong dimasukkan.

Fabian Schmengler
sumber
1

PHP, 362 367 Bytes

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

Versi yang diformat:

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

Garis yang menarik:

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

Mengonversi satu karakter UTF-8 ke nilai byte dan menjumlahkannya, sehingga kami mendapatkan nilai nyata untuk karakter ASCII dan nilai yang lebih tinggi dari 127 untuk karakter 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;

Memanfaatkan operator yang lebih rendah dari anddan oruntuk menetapkan nilai karakter dalam satu pernyataan tanpa if.

Fabian Schmengler
sumber
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)}<>)

Cobalah online!

Xcali
sumber