クレイジーライブラリアンのすばらしい仕分けシステム


21

学校シーズンに戻りました!アルバイトの場合、学校の図書館で手伝っています。問題は、主任司書が「デューイ十進法」という言葉さえ聞いたことがないことであり、そのシステムを実装したことは言うまでもない。代わりに、ライブラリが拡大するにつれて、使用中の分類システムが「有機的に」成長しました...

あなたの正気を保つために、あなたは本が返されるときに本を分類するのを助けるプログラムを書くことを選んだ。(ヘッドライブラリアンは非常に厳格です。)

入出力

  • 入力は、STDIN /同等の言語からの(架空の)書籍タイトルのリストで、1行に1つずつです。
  • 一度に入力できるのは100冊までです(一度に多くの本を図書館に持ち込むことができます)。
  • 書籍のタイトルには複数の単語を含めることができ、これらの単語はスペースまたはその他の句読点(コロン:、ダッシュ-など)で区切ることができます。
  • 計算を簡単にするために、すべてのタイトルがUTF-8であると想定します。

出力は同じタイトルで、以下のルールに従ってソートされ、再び1行に1つずつ、STDOUT /言語に相当します。

ソート規則

書籍は、平均文字値(つまり、累積文字値を書籍タイトルの文字数で割った値)に基づいて数値順にソートされ、次の規則に従ってカウントされます。

  • すべての文字は、タイトルの文字数を決定するためにカウントされます。
  • 小文字は、アルファベットの位置によってカウントされます。(a = 1、b = 2、... z = 26)
  • タイトルに大文字が含まれる場合、それらは小文字の値(A = 1.5、B = 3、... Z = 39)の1.5としてカウントされます。(「大文字が重要です!」司書は言います。)
  • このリストの各句読点/記号は、!@#$%^&*()-=_+[]\{}|;':",./<>?~平均する前に累積値から-1をカウントします。(「壮大なタイトルは違います!」)
  • タイトルにアラビア数字で書かれた数字が含まれている場合、ソートする前にその数字が平均値から差し引かれます。複数の連続した数字は1つの数字として扱われます(たとえば、424を減算してから2を減算するのではなく、42を減算します)。個々の数字は累積値にはカウントされません(つまり、各数字は0に寄与します)が、DOは文字数にカウントされます。これは負の値になる可能性があるため、適切に処理する必要があることに注意してください。(噂によると、司書は数年前から数学のインストラクターに夢中になっている。)
  • タイトルにで始まる2つの単語が含まれているR場合、本は「無限」のスコアを取得し、コーナーの山に捨てられます(つまり、リストの最後にランダムに配置されます)。(司書は、それらのイニシャルを持つ人によってかつて投げ捨てられた、またはあなたは聞いたことがあります。)
  • スペースは、累積文字値にはカウントされません(つまり、0は寄与します)が、タイトルの文字数には寄与します。
  • 上記のルールに適合しない文字(例:a ÿ)は、累積文字値にはカウントされません(つまり、0に寄与します)が、タイトルの文字数には寄与します。
  • たとえば、架空の本ÿÿÿÿÿにはの「スコア」が(0+0+0+0+0) / 5 = 0ありますが、架空の本ÿÿyÿÿにはの「スコア」があり(0+0+25+0+0) / 5 = 5ます。
  • 偶然同じ「スコア」の2冊の本を、選択した順序で出力できます。(とにかく同じ棚にあります)

入力例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にすべての時間を費やすことで、図書館員に怠け者を捕まえさせないでください。

2冊の本のスコアがまったく同じ場合はどうなりますか。すなわち、私は虹とルビーのレールを読んでいます
Kishan Kumar

@KishanKumarその特定のインスタンスでは、「リストの最後にランダムに配置」されています。どちらもダブルRであるためです。言い換えれば、あなたの選んでください。一般的な場合、2つの単語のスコアが同じである場合、それらは互いに相対的な順序で表示されます。それを明確にするために箇条書きを追加します。
AdmBorkBork

7
システムに頭字語名を付けるには、Aワードが必要です。Crazy Librarianのすばらしい並べ替えシステムをお勧めします:D
Geobits

3
@Geobitsクラスはありますか?
AdmBorkBork

数字は単なる10進数ですか?複数のものがある場合、それらはすべて個別に減算されますか?
パエロエベルマン

回答:


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:セット⎕ML3(用
  • ⍵[⍋{... }¨⍵]:入力を内部関数から返された値でソートします
    • ↑¨⍵⊂⍨⍵≠' ':各単語の最初の文字を取得
    • 2='R'+.=:これらの2つが'R'
    • :!99:その場合、99を返します!(≈9.3×10 155)。これは完全な無限ではありませんが、そうです:タイトルの長さが38倍(ZZZZ ...)を超えることはありません。1つのタイトルが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',:add '0'、リストが空にならないようにする
      • ⍎¨:各文字列を評価する
      • +/:合計を見つける

代わりに!99使用することができます⌊/⍬
アダム

1
APLで長いコードを見るのが大好きです。世界は私よりもはるかに大きいように感じます。そして、シンボルが好きです。
コナーオブライエン

2

Lua 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

このコードはUnicode文字を処理する必要があるため、Lua 5.3でのみ機能します。Unicodeを気にしない場合は、「utf8」を「string」に置き換えれば、Lua 5.2または5.1で正常に機能します。

コマンドライン引数から入力を受け取るため、コマンドラインから実行するか、このコードを私の答えの上に置きます:

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

私のマシンにはLua 5.3がありませんが、あなたの提案に従ってIdeoneで交換utf8stringましたが、出力はありませんでした。
AdmBorkBork

@TimmyD私の編集を見る
Trebuchette

良い。グレービー。そして(arg)、顔を凝視してそこに座っています。この質問はどうやら私の脳を揚げたようです。+1します。
AdmBorkBork

:MoonScriptで、これは266バイトですpastebin.com/wr4qVs5h
kirbyfan64sos

2

Mathematica、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のパターンマッチングは、文字列が関係しているときほど簡潔ではなく、私はそれらの長い名前に殺されてしまいます。余分な2バイトはInfinityUnicode文字用です。

(標準の抜け穴に違反したかどうかを教えてください。)

更新

edc65の答えをもう少し詳しく見ると、OPは文字列のリストをソートする関数を受け入れるようです。それを念頭に置いて、カリー化された形式SortByMathematicaを「演算子形式」と呼びます)を使用できます。1つの引数(リスト要素に適用されて順序を決定する関数)を使用すると、1つの引数を取り、ソートされた形式の入力を返す関数のように動作します。つまり、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.innerHTMLthis.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バイトを節約できます。

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

Go、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;

作るには、低演算子の優先順位の使用andorすることなく、単一の文で文字の値を代入しますif


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.