疯狂的图书管理员的惊人分类系统


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),但确实对标题中的字符数有所贡献。
  • 不符合上述规则的字符(例如a ÿ)不会计入字符的累积值(即,它们贡献0),但确实会增加标题中的字符数。
  • 例如,假设的书ÿÿÿÿÿ的“分数”为(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上让你放松下来。

如果两本书得分完全相同怎么办。即我已经读过Rainbow和Ruby Rails
Kishan Kumar

@KishanKumar在该特定实例中,“它们随机排列在列表的末尾”,因为它们都是double-R。换句话说,请选择。在一般情况下,如果两个单词得分相同,则它们可以相对于彼此的任何顺序出现。我将添加一个项目符号来澄清这一点。
AdmBorkBork 2015年

7
您需要一个单词,以便您的系统使用首字母缩写名称。我推荐Crazy Librarian的Amazing Sorting System:D
Geobits,2015年

3
@Geobits你有CLASS吗?
AdmBorkBork 2015年

数字只是十进制数字吗?如果有几个,将它们分别减去怎么办?
圣保罗Ebermann

Answers:


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'+.=:看看是否有两个是'R'
    • :!99:如果是,则返回99!(≈9.3×10 155)。这不是无限,而是可以做到的:标题的总分不能超过其长度的38倍(ZZZZ ...),因此,只要没有一个标题的总分大于2×10 130 yottabytes,它就可以保证这些将在最后。
    • : 除此以外:
    • (... )÷⍴⍵:将分数除以计算后的长度:
      • 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您可以使用⌊/⍬
2015年

1
我喜欢看APL中的长代码。这让我觉得世界比我大得多。我喜欢符号。
Conor O'Brien 2015年

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

该代码仅在Lua 5.3中有效,因为它需要处理Unicode字符。如果您不关心Unicode,则将“ utf8”替换为“ string”,它将在Lua 5.2或5.1中正常工作。

它从命令行参数获取输入,因此要么从命令行运行它,要么将此代码放在我的答案上方:

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

我没有Lua的5.3我的机器上,但我也跟着你的建议,以交换utf8stringIdeone并没有得到输出。
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的模式匹配并不那么简洁,而我只是被那些长名称杀死了。多余的两个字节用于InfinityUnicode字符。

(让我知道我是否违反了任何“标准漏洞”。)

更新资料

仔细看一下edc65的答案,看起来OP会接受对字符串列表进行排序的函数。考虑到这一点,我们可以使用的咖喱形式SortByMathematica称之为“运营商形式”);带有一个参数(应用于列表元素以确定其顺序的函数),其行为就像一个接受一个参数的函数,返回输入的排序形式;即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
很好的答案,您会得到一个Internet Cookie,因为它在计算中实际上使用了“ infinity” ;-)。
AdmBorkBork,2015年

@TimmyD符号数学处理的美丽=)
2012rcampion 2015年

可能是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>


做得很好。为了供其他人阅读此答案,我必须在Firefox的控制台中更改O.innerHTMLthis.InnerHTML
AdmBorkBork,2015年

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

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


1

Perl 5,190字节

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

在线尝试!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.