Çılgın Kütüphanecinin İnanılmaz Sıralama Sistemi


21

Okul sezonuna geri döndü! Yani yarı zamanlı bir iş için okulun kütüphanesinde yardım ediyorsun. Sorun şu ki, baş kütüphaneci "Dewey Ondalık" kelimesini hiç duymamış bile olsa, bu sistemi uyguladı. Bunun yerine, kullanılan sıralama sistemi, kütüphane genişledikçe "organik olarak" büyüdü

Akıl sağlığınızı korumak için, kitapları geri gönderildiği gibi sıralamanıza yardımcı olacak bir program yazmayı seçtiniz, çünkü kitapları yanlış sıralarsanız, size aittir. (Baş kütüphaneci ÇOK katıdır.)

Giriş çıkış

  • Girdi, STDIN / dil eşdeğerinden, her satırda bir tane olmak üzere (varsayımsal) kitap başlıklarının bir listesi olacaktır.
  • Bir seferde 100'den fazla kitap girişi olmadığını varsayabilirsiniz (kütüphanede sadece bir defada çok fazla taşıyabilirsiniz).
  • Kitaplar başlıklarında birden fazla kelime içerebilir ve bu kelimeler boşluklarla veya başka noktalama işaretleriyle (örn. İki nokta üst üste :, kısa- . vb.) .
  • Hesaplama kolaylığı için, tüm başlıkların UTF-8 olduğunu varsayalım.

Çıktı, aşağıdaki kurallara göre, her satırda bir kez olmak üzere, STDOUT / dil eşdeğeri olarak sıralanan aynı başlıklardır.

Sıralama Kuralları

Kitaplar, ortalama karakter değerlerine göre (yani, toplam karakter değeri kitap başlığındaki karakter sayısını bölünür) temel alarak aşağıdaki kurallara göre sayılır:

  • Tüm karakterler, bir başlıktaki karakter sayısını belirlemek için sayılır.
  • Küçük harfler, alfabedeki konumlarına göre sayılır. (A = 1, b = 2, ... Z = 26)
  • Başlık büyük harf içeriyorsa, bunlar küçük harflerin değeri 1.5'tir (A = 1.5, B = 3, ... Z = 39). (“Büyük harfler önemlidir!” Diyor kütüphaneci.)
  • Bu listedeki her noktalama işareti / sembolü, !@#$%^&*()-=_+[]\{}|;':",./<>?~ortalama almadan önce kümülatif değerden -1 sayılır. ("Görkemli başlıklar değil!")
  • Başlık, Arap rakamlarıyla yazılmış bir sayı içeriyorsa , bu sayı sıralamadan önce ortalama değerden çıkarılır. Birden fazla ardışık basamak, tek bir sayı olarak değerlendirilir (örneğin, 424 çıkarmadan sonra 42'yi çıkarır ve daha sonra 2'yi çıkarır). Tek tek rakamlar kümülatif değer için sayılmaz (yani, her rakam 0 katkıda bulunur), ancak DO karakter sayısı için sayılır. Bunun negatif bir değere yol açabileceğini ve uygun şekilde ele alınması gerektiğini unutmayın. (Söylentiye göre, kütüphaneci birkaç yıldır matematik öğretmenine aşık oldu.)
  • Başlık bir ile başlayan iki ayrı sözcük içeriyorsa R, kitap "sonsuzluk" puanı alır ve köşedeki bir yığının içine dökülür (yani listenin sonunda rastgele düzenlenir). (Kütüphaneci bir zamanlar bu baş harfleri olan bir kişi tarafından terk edilmişti ya da siz duydunuz.)
  • Boşluklar, kümülatif karakter değeri için sayılmaz (yani, 0 katkıda bulunurlar), ancak DO, başlıktaki karakter sayısına katkıda bulunur.
  • Yukarıdaki kurallara uymayan karakterler (örneğin, a ÿ) kümülatif karakter değerine sayılmaz (yani, 0 katkıda bulunurlar), ancak bir başlıktaki karakter sayısına DO katkıda bulunur.
  • Örneğin, varsayımsal bir kitabın ÿÿÿÿÿ"puanı" olur (0+0+0+0+0) / 5 = 0, ancak varsayımsal kitabın ÿÿyÿÿ"puanı" olur (0+0+25+0+0) / 5 = 5.
  • Aynı "puan" olan iki kitap, istediğiniz seçimde Çıktı olabilir. (Yine de aynı raftalar)

Örnek Giriş 1

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

Örnek Çıktı 1 (gerekçeleri göstermek için parantez içindeki "puanlar" ile - bunları yazdırmanız gerekmez)

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

Örnek Giriş 2

Matthew
Mark
Luke
John
Revelations

Örnek Çıktı 2 (gerekçeleri göstermek için parantez içindeki "puan" ile - bunları yazdırmanız gerekmez)

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

Örnek Giriş 3

42
9 Kings
1:8
7th

Örnek Çıktı 3 (gerekçeleri göstermek için parantez içindeki "puanlar" ile - bunları yazdırmanız gerekmez)

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

Diğer kısıtlamalar

  • Bu Kod Golf'tür, çünkü programı kütüphanecinin sürekli izleyen gözlerinden gizlemeniz gerekir ve program ne kadar küçükse, saklanması o kadar kolay olur.
  • Standart boşluk deliği kısıtlamaları uygulanır
  • Bütün zamanını PPCG'de geçirerek kütüphanecinin seni gevşetmesine izin verme.

Ya iki kitap tam olarak aynı puan alırsa. yani, Rainbow ve Ruby Raylarını Okudum
Kishan Kumar

@KishanKumar Bu özel örnekte, her ikisi de çift R olduğundan bu yana, "listenin sonunda rastgele düzenlenmiş". Başka bir deyişle, istediğini al. Genel durumda, iki kelime aynı puan alırsa, birbirlerine göre herhangi bir sırayla görünebilirler. Bunu netleştirmek için bir mermi ekleyeceğim.
AdmBorkBork

7
Bir kelimeye ihtiyacınız var, sisteminizde bir kısaltma adı olsun. D: Ben Çılgın Kütüphaneciler Şaşırtıcı Tasnif Sistemi tavsiye
Geobits

3
@Geobits SINIF var mı?
AdmBorkBork,

Sayılar sadece ondalık sayılar mı? Ya birkaç tane varsa hepsi ayrı ayrı çıkarılırsa?
Paŭlo Ebermann 16:15

Yanıtlar:


5

APL (132)

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

Diğer herkes aynı şeyi yaptığı için, bu aynı zamanda bir dizi başlığı alan ve dizilişini döndüren bir işlevdir, örneğin:

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

Açıklama:

  • ⎕ML←3: Set ⎕MLiçin 3(için )
  • ⍵[⍋{... }¨⍵]: girişi iç işlevden döndürülen değerlere göre sırala
    • ↑¨⍵⊂⍨⍵≠' ': her kelimenin ilk karakterini al
    • 2='R'+.=: bunlardan ikisinin olup olmadığını görün 'R'.
    • :!99: öyleyse, 99 döndür! (≈ 9.3 × 10 155 ). Bu tam bir sonsuzluk değildir, ancak yapacaktır: bir başlık asla uzunluğunun 38 katından (ZZZZ ...) fazla puan alamaz, yani hiçbir başlık yaklaşık 2 × 10 130 yottabayttan daha büyük olmadığı sürece, bunların sonunda olacağı garanti edilmektedir.
    • : aksi takdirde:
    • (... )÷⍴⍵: hesapladıktan sonra puan uzunluğuna bölün :
      • G←(⊂⎕A),(⎕UCS 96+⍳26): Gbüyük ve küçük harflerde saklayın
      • (⎕UCS 32+⍳94)~'`',⎕D,∊G: yazdırılabilir ASCII karakterleri, harfler, rakamlar, boşluklar ve '`'bir noktanın çıkartıldığı karakterler. (Bu hepsini yazmaktan daha kısadır, çünkü Gdaha sonra kullanılır.)
      • +/⍵∊: bu karakterlerin miktarını
      • -: bunu şunlardan çıkarın:
      • +/∊1.5 1×(⍳×∊⍨)∘⍵¨G: Büyük harflerin puanlarının 1,5 ×, küçük harflerin ise puanlarının toplamı 1 ×.
    • -⍨: sonra, içindeki sayıların toplamını çıkarın :
      • ⍵⊂⍨⍵∊⎕D: içindeki rakam gruplarını bul
      • '0',: '0'listenin boş kalmasını önlemek için ekle
      • ⍎¨: her dizgiyi değerlendirin
      • +/: toplamı bul

Yerine !99kullanabilirsiniz⌊/⍬
Adám

1
APL’de uzun koda bakmayı seviyorum. Bana dünyayı benden çok büyük gibi hissettiriyor. Ve ben sembollerden hoşlanıyorum.
Conor O'Brien,

2

Lua 5.3, 366 364 Bayt

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

Bu kod yalnızca Lua 5.3'te çalışır, çünkü Unicode karakterleriyle başa çıkması gerekir. Unicode'u umursamıyorsanız, "utf8" i "string" ile değiştirin ve Lua 5.2 veya 5.1 ile iyi çalışacaktır.

Girdilerini komut satırı argümanlarından alır, bu nedenle ya komut satırından çalıştırın ya da bu kodu cevabımın üzerine koyun:

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

Benim makinede Lua 5.3 yok ama takas için öneri takip utf8ile stringilgili Ideone ve hiçbir çıkış var.
AdmBorkBork,

Benim düzenlemeyi bkz @TimmyD
Trebuchette

İyi. Sos. Ve (arg)orda oturmuş suratıma bakıyordu. Bu soru görünüşte beynimi kızarttı. + 1'leyin.
AdmBorkBork 16:15

MoonScript ile bu 266 bayttır: pastebin.com/wr4qVs5h .
kirbyfan64sos

2

Mathematica, 253 216 bayt (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@#]&]

Gibi işlevi çağırın f[{"42", "9 Kings", "1:8", "7th"}]; girişlerin sıralanmış bir listesini döndürür.

Sadece zar zor başardı! Mathematica'nın örüntü eşleştirmesi, dizeler söz konusu olduğunda özlü değildir ve ben sadece bu uzun isimler tarafından öldürülüyorum. Fazladan iki bayt Infinityunicode karakter içindir.

(Herhangi bir Standart Loopholes’a karşı bir hata yaptığımda bana haber verin.)

Güncelleştirme

Edc65'in cevabına biraz daha yakından baktığımızda, OP dizelerin listesini sıralayan bir işlevi kabul edecek gibi görünüyor. Bunu akılda tutarak SortBy( Mathematica'nın "işleç formu" olarak adlandırdığı) curried formunu kullanabiliriz ; bir argümanla (sırasını belirlemek için liste öğelerine uygulanan işlev) bir argüman alan, girişin sıralanmış biçimini döndüren bir işlev gibi davranır; yani, SortBy[list, f]eşdeğerdir (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
Güzel cevap, ve hesaplamalarınızda kelimenin tam anlamıyla "sonsuzluğu" kullandığınız için bir İnternet Çerezine sahip olursunuz ;-).
AdmBorkBork

@TimmyD Sembolik matematik işlemenin güzelliği =)
2012rcampion

Muhtemelen 214 karakter, 216 bayt demek istiyorsun. Aferin, rekabet etmeye çalıştım ama olmadı
edc65

2

JavaScript (ES6), 210 218 251

Bir dizi argümanına sahip bir fonksiyon olarak, sıralı olarak geri döndü.

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>


Güzel bitti. Bu cevabı okuyan başkalarına referans vermek O.innerHTMLiçin this.InnerHTMLFirefox konsolunda değişiklik yapmak zorunda kaldım .
AdmBorkBork

1

C #, 352 349 Bayt

Linq büyüsü nedeniyle:

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

Noktalama işaretleri noktalama işaretine dahil edildiyse 6 bayt daha kaydedilmiş olabilir!

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

755 Bayt

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

Biçimlendirilmiş versiyonu:

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

Özel bir sıralama arayüzü uygulamak beklenenden daha uzun sürdü. Program boş bir satır girilene kadar STDIN'den okur.


1

PHP, 362 367 Bayt

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

Biçimlendirilmiş versiyon:

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

İlginç çizgiler:

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

Tek bir UTF-8 karakterini bayt değerlerine dönüştürür ve toplar, böylece ASCII karakterleri için gerçek değeri ve çok baytlı karakterleri için 127'den yüksek bir değeri elde ederiz.

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;

Markalar düşük operatör öncelik kullanmak andve orolmadan tek açıklamada karakter değerini atamak if.


1

Perl 5 , 190 bayt

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

Çevrimiçi deneyin!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.