Дивовижна система сортування божевільного бібліотекаря


21

Повернувся до шкільного сезону! Тож для неповної роботи вам допомагають у шкільній бібліотеці. Проблема в тому, що головний бібліотекар ніколи навіть не чув слів "Дьюї Десятковий", не кажучи вже про реалізацію цієї системи. Натомість система сортування, яка використовується, зросла "органічно", оскільки бібліотека розширилась ...

Прагнучи зберегти свій розум, ви вирішили написати програму, яка допоможе вам сортувати книги по мірі повернення, бо горе вам, якщо ви сортуєте книги неправильно. (Головний бібліотекар ДУЖЕ суворий.)

Введення-виведення

  • Вхідними даними буде список (гіпотетичних) назв книг, по одному на рядок, з STDIN / мовного еквівалента.
  • Ви можете припустити не більше 100 книг, введених одночасно (ви можете переносити стільки стільки по бібліотеці одночасно).
  • Книги можуть мати кілька слів у своїх заголовках, і ці слова можуть бути розділені пробілами чи іншими розділовими знаками (наприклад, двокрапка :, тире -тощо).
  • Для зручності обчислення припустимо, що всі заголовки є UTF-8.

Вихід - це ті самі заголовки, відсортовані за наведеними нижче правилами, знову по одному на рядок, до STDOUT / мовний еквівалент.

Правила сортування

Книги впорядковуються чисельно на основі їх середнього значення символу (тобто, сукупне значення символів, поділене на кількість символів у заголовку книги), підраховане за такими правилами:

  • Усі символи враховуються для визначення кількості символів у заголовку.
  • Малі літери підраховуються за їх положенням в алфавіті. (a = 1, b = 2, ... z = 26)
  • Якщо заголовок містить великі літери, ці рахунки становлять 1,5 їхнього малого значення (A = 1,5, B = 3, ... Z = 39). («Великі літери важливі! - каже бібліотекар.)
  • Кожен розділовий знак / символ у цьому списку !@#$%^&*()-=_+[]\{}|;':",./<>?~нараховує -1 від сукупного значення перед усередненням. ("Грандіозних назв немає!")
  • Якщо заголовок містить число, написане арабськими цифрами , це число віднімається від середнього значення перед сортуванням. Кілька послідовних цифр трактуються як одне число (наприклад, 42віднімають 42, а не віднімають 4, а потім віднімають 2). Індивідуальні цифри не враховуються за сумарним значенням (тобто кожна цифра вносить 0), але DO рахують для кількості символів. Зауважте, що це може призвести до негативного значення і до нього слід поводитися належним чином. (Подейкують, у бібліотекаря вже кілька років пригнічується інструктор з математики.)
  • Якщо заголовок містить два окремі слова, які починаються з R, книга отримує оцінку "нескінченності" і скидається в купу в кутку (тобто, випадковим чином розташовується в кінці списку). (Колись бібліотекаря скинула людина з цими ініціалами, або так ви чули.)
  • Пробіли не враховуються для сукупного значення символів (тобто вони вносять 0), але DO вносять кількість символів у заголовку.
  • Символи, які не відповідають наведеним вище правилам (наприклад, а ÿ), не враховують сукупне значення символів (тобто вони вносять 0), але DO вносять кількість символів у заголовку.
  • Наприклад, гіпотетична книга ÿÿÿÿÿматиме "бал" (0+0+0+0+0) / 5 = 0, а гіпотетична книга ÿÿyÿÿ- "оцінка" (0+0+25+0+0) / 5 = 5.
  • Дві книги, які "набрали" те саме, можуть бути результатами на ваш вибір. (У будь-якому випадку вони на одній полиці)

Приклад введення 1

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

Приклад Вихід 1 (з "балами" в дужках, щоб показати міркування - не потрібно їх друкувати)

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

Приклад введення 2

Matthew
Mark
Luke
John
Revelations

Приклад Вихід 2 (з "балами" в дужках, щоб показати міркування - не потрібно їх друкувати)

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

Приклад введення 3

42
9 Kings
1:8
7th

Приклад Виведення 3 (з "балами" в дужках, щоб показати міркування - не потрібно їх друкувати)

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

Інші обмеження

  • Це Code-Golf, тому що потрібно зберігати програму в таємниці від постійно спостерігаючих очей бібліотекаря, і чим менше програма, тим простіше її приховати.
  • Застосовуються стандартні обмеження лазівки
  • Не дозволяйте бібліотекару наздоганяти вас, витрачаючи весь свій час на PPCG.

Що робити, якщо дві книги набрали точно стільки ж. тобто я читаю Рейки з
веселками

@KishanKumar У цьому конкретному екземплярі "випадковим чином розташовані в кінці списку", оскільки вони обидва подвійні R. Іншими словами, прийміть свій вибір. У загальному випадку, якщо два слова набирають однаково, вони можуть з’являтися в будь-якому порядку відносно один одного. Я додам кулю, щоб уточнити це.
AdmBorkBork

7
Вам потрібне слово A, щоб ваша система мала назву абревіатури. Я рекомендую дивовижну систему сортування божевільного бібліотекаря: D
Geobits

3
@Geobits У вас є КЛАС?
AdmBorkBork

Числа - це лише десяткові числа? Що робити, якщо їх кілька, чи всі вони віднімаються окремо?
Paŭlo Ebermann

Відповіді:


5

APL (132)

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

Оскільки всі інші роблять те саме, це теж є функцією, яка приймає масив заголовків і повертає їх сортованими, наприклад:

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

Пояснення:

  • ⎕ML←3: Встановити ⎕MLв 3(для )
  • ⍵[⍋{... }¨⍵]: сортуйте вхід за значеннями, поверненими з внутрішньої функції
    • ↑¨⍵⊂⍨⍵≠' ': отримати перший символ кожного слова
    • 2='R'+.=: подивіться, чи є два з них 'R'.
    • :!99: якщо так, поверніть 99! (≈ 9,3 × 10 155 ). Це не зовсім нескінченно, але це дійсно: заголовок ніколи не може мати бал більше 38 разів перевищує його довжину (ZZZZ ...), якщо поки жоден заголовок не перевищує приблизно 2 × 10 130 йотабайт, він гарантується, що вони будуть наприкінці.
    • : інакше:
    • (... )÷⍴⍵: розділити бал на довжину після його обчислення:
      • G←(⊂⎕A),(⎕UCS 96+⍳26): зберігати в G великих і малих літерах
      • (⎕UCS 32+⍳94)~'`',⎕D,∊G: символи для друку ASCII, крім букв, цифр, пробілів та '`'символів, для яких віднімається точка. (Це коротше, ніж виписати їх усіх, боG вони використовуються згодом.)
      • +/⍵∊: підрахуйте кількість цих символів у
      • -: відняти це від:
      • +/∊1.5 1×(⍳×∊⍨)∘⍵¨G: сума 1,5 × балів для великих літер та 1 × балів для малих літер.
    • -⍨: потім відніміть загальну кількість чисел у :
      • ⍵⊂⍨⍵∊⎕D: знайдіть групи цифр у
      • '0',: додати '0', щоб запобігти порожньому списку
      • ⍎¨: оцінюйте кожен рядок
      • +/: знайти суму

Замість того, щоб !99ви могли використовувати⌊/⍬
Adám

1
Я люблю дивитись довгий код в APL. Це змушує мене відчувати, що світ настільки великий, ніж я. І мені подобаються символи.
Conor O'Brien

2

Луа 5.3, 366 364 байт

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

Цей код працює лише в Lua 5.3, оскільки йому потрібно мати справу з символами Unicode. Якщо ви не переймаєтеся Unicode, замініть "utf8" на "string", і це буде добре працювати з Lua 5.2 або 5.1.

Він бере свої дані з аргументів командного рядка, тому або запустіть його з командного рядка, або поставте цей код над моєю відповіддю:

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

Я не Lua 5.3 на моїй машині, але я пішов за вашу пропозицію поміняти місцями utf8з stringна Ideone і не отримав ніякого висновку.
AdmBorkBork

@TimmyD дивись мою редакцію
Trebuchette

Добре. Граві. І (arg)сидить там, дивлячись мені в обличчя. Це питання, мабуть, обсмажило мій мозок. Майте +1.
AdmBorkBork

З MoonScript це 266 байт: pastebin.com/wr4qVs5h .
kirbyfan64sos

2

Математика, 253 216 байт (214 символів)

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

Викликайте функцію типу f[{"42", "9 Kings", "1:8", "7th"}]; він поверне відсортований список входів.

Тільки ледве встигли! Відповідність шаблону Mathematica не є такою стислою, коли залучаються рядки, і мене просто вбивають ці довгі імена. Додаткові два байти для Infinityсимволу unicode.

(Дайте мені знати, чи я зіткнувся з будь-якими стандартними лазівками.)

Оновлення

Придивившись трохи ближче до відповіді edc65, схоже, що ОП прийме функцію, яка сортує список рядків. Зважаючи на це, ми можемо використовувати викриту форму SortBy(яку Mathematica називає "формою оператора"); з одним аргументом (функція, застосована до елементів списку для визначення їх порядку), вона поводиться як функція, яка бере один аргумент, повертаючи відсортовану форму вводу; це є,SortBy[list, f] еквівалентний (SortBy[f])[list].

Безумовно

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
Гарна відповідь, і ви отримуєте Інтернет-cookie за буквальне використання "нескінченності" у своїх розрахунках ;-).
AdmBorkBork

@TimmyD Краса символічної обробки математики =)
2012rcampion

Напевно, ви маєте на увазі 214 символів, 216 байт. Молодці, я намагався змагатися, але ніяк
edc65

2

JavaScript (ES6), 210 218 251

Як функція з аргументом масиву, повертається відсортовано.

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>


Чудово зроблено. Для посилання на когось іншого, хто читає цю відповідь, мені довелося перейти O.innerHTMLна this.InnerHTMLконсоль Firefox.
AdmBorkBork

1

C #, 352 349 байт

Завдяки магії 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);}}

Могли б зберегти ще 6 байт, якби backtick був включений до пунктуаційного списку!

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 байт

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

Відформатована версія:

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

Реалізація користувальницького інтерфейсу сортування зробила його довшим, ніж очікувалося. Програма читає з STDIN до кінця введення чи порожнього рядка.


1

PHP, 362 367 Байти

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

Відформатована версія:

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

Цікаві рядки:

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

Перетворює один символ UTF-8 у його байтові значення та підсумовує їх, так що ми отримуємо реальне значення для символів ASCII та значення вище 127 для багатобайтових символів.

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;

Використовує низький пріоритет оператора andта orпризначає значення символу в одному операторі без if.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.