查找一组字符串的所有明确前缀


12

为了应对这一挑战,您必须Abbrev以尽可能少的代码来实现Ruby的模块。

挑战

  • 输入将是您的语言作为字符串数组(数组,列表,序列等)所具有的内容。您可以编写函数,也可以在STDIN上接受逗号分隔的单词。

  • 然后,您必须为这些字符串计算一组明确的前缀。这意味着您必须将缩写的哈希值(或映射,对象等)返回到其原始字符串。

    • “前缀”是原始字符串的子字符串,从字符串的开头开始。例如,“ pref”是单词“ prefix”的前缀。

    • 一个明确的前缀是一个只能意味着一个字。例如,如果您输入的是car,cat,则ca前缀不是明确的,因为它可能表示“ car”或“ cat”。

    • 该规则的例外是单词始终是其自身的前缀。例如,如果输入中有诸如car,carpet,则car:car必须在输出中。

  • 然后,您可以返回哈希/地图/对象/等。从您的函数(或使用您的语言进行等效操作)中,或以key:value形式成对打印到STDOUT中f:foo,fo:foo,...。(如果键/值对使您的代码更短,也可以将它们分隔开。)

测试用例

Input  code,golf,going
Output c:code,co:code,cod:code,code:code,gol:golf,golf:golf,goi:going,goin:going,going:going

Input  pie
Output p:pie,pi:pie,pie:pie

Input  pie,pier,pierre
Output pie:pie,pier:pier,pierr:pierre,pierre:pierre

Input  a,dog
Output a:a,d:dog,do:dog,dog:dog

规则

  • 输入将不包含重复的元素。

  • 您的输出可以是任何顺序;您不必对其进行排序。

  • 您可能不使用内置Abbrev模块/函数/ Ruby之类的东西。

  • 这是,因此最短的代码(以字节为单位)将获胜!


stdout是否必须正是该格式?还是我可以key:value\nkey:value\nkey:value...?
Undergroundmonorail

4
除了重新定义单词缩写外,您还可以使用具有标准含义的前缀。而且我认为,明确表示键比唯一表示键更有效传达键的期望属性,对此我的直觉是,每个输入单词只需要一个前缀。
彼得·泰勒

@PeterTaylor好主意;编辑。
门把手

1
一个人可以多次打印相同的键(具有相同的值)吗?
xnor 2014年

Answers:


1

APL(46)

(是的,APL字符集确实适合一个字节,并有剩余空间。)

{↑{∆/⍨2=⍴∆←(⊂⍵),∆/⍨⊃¨⍵∘⍷¨∆}¨∪⊃,/{↑∘⍵¨⍳⍴⍵}¨∆←⍵}

该函数需要一个字符串列表,并返回一个2×N矩阵,其中每行包含一个明确的前缀及其所属的单词:

{↑{∆/⍨2=⍴∆←(⊂⍵),∆/⍨⊃¨⍵∘⍷¨∆}¨∪⊃,/{↑∘⍵¨⍳⍴⍵}¨∆←⍵}'code' 'golf' 'going'
 c      code  
 co     code  
 cod    code  
 code   code   
 gol    golf  
 golf   golf  
 goi    going 
 goin   going 
 going  going 

说明:

  • ∆←⍵:将正确的参数存储在中
  • {↑∘⍵¨⍳⍴⍵}¨∆:对于的每个元素,获取该元素的可能前缀:
    • ⍳⍴⍵:获取列表1,其长度为
    • ↑∘⍵¨:对于每个数字,从中获得那么多元素
  • ∪⊃,/:将列表串联在一起并采用唯一值。
  • {... :对于每个唯一前缀:
    • ∆/⍨⊃¨⍵∘⍷¨∆:选择以该前缀开头的单词
    • (⊂⍵),:还包含前缀并连接
    • ∆/⍨2=⍴∆←:仅在有两个元素(前缀和一个匹配词)的情况下返回列表
  • :将元组列表转换为矩阵

现在,链接已断开...
user202729 '18

3

Python 2.7版- 146个 141字节

l=raw_input().split(',')
for w in l:
 for a in range(len(w)):
    e=w[:a+1]
    if e==w or len(filter(lambda b:b.startswith(e),l))==1:print e+':'+w

请注意,第4行和第5行的缩进不是4个空格,这是SE的markdown解释器的副作用。那是一个文字制表符,所以只有一个字节。

从技术上讲,这不符合规范,但如果Doorknob明确说明,我将对其进行更改。它使用换行符而不是逗号来分隔输出。例如:

$ python2 abbreviations.py <<< code,golf,golfing
c:code
co:code
cod:code
code:code
golf:golf
golfi:golfing
golfin:golfing
golfing:golfing

新增内容:通过将要检查的字符串分配给变量,我摆脱了5个字符e。这意味着我只需要键入e而不是w[:a]三次。这也意味着我可以通过e=w[:a+1]更改...range(1,len(w)+1)为来保存字符range(len(w))


说明:

l=raw_input().split(',') # Gets a line of input from stdin and splits it at every ',' to make a list
for w in l: # For each word in that list...

 for a in range(1,len(w)+1): # For each number a from 1 to the length of that word...

    if (w[:a]==w # w[:a] gets the string w up to the ath index. For example, 'aeiou'[:3] == 'aei'.
                 # We're testing every possible w[:a] to see if it's a unique abbreviation.
                 # However, a word is always its own abbreviation, so we hardcode that in by testing
                 # if w[:a] is the same as w.

or len(filter( # filter takes a function and an iterable as an argument, and returns a list of every
               # element of that iterable where that_function(that_element) returns a True-y value

lambda b:b.startswith(w[:a]),l) # We define an anonymous function that returns True for any string
                                # that begins with our current w[:a]. We filter for words that return
                                # True.

)==1): # If exactly one word returns True for this, it's a unique abbreviation!

     print w[:a]+':'+w # Print the abbreviation, a colon, and the full word.

你可以使用sum(b.startswith(e) for b in l),而不是len(filter(lambda b:b.startswith(e),l))
尼克拉斯B.

您也可以缩短b.startswith(e)b.find(e)==0b[:a+1]==e,然后检查<2计数而不是==1
xnor 2014年

也可以这样做e=""\n for a in w:\n\te+=afor a in range(len(w)):\n\te=w[:a+1]因为它可以节省10个字符
WorldSEnder 2014年

我为需要它的任何人在这里制作了未胶化的版本 gist.github.com/stuaxo/c371b2d410191a575b763b74719856c8
Stuart Axon

3

J-47个字符

(,.~~.@,~[:(#~1-1({.\e."_1]\.){."1)@;(<\,.<)&.>)

J将字符串视为字符的向量,这意味着当它尝试创建字符串列表时,实际上实际上是形成了一个字符表,因此两端都填充了空格。J对此的解决方案称为box,因此此函数将一个装箱的字符串列表作为参数,以保留长度。

   'code';'golf';'going'
+----+----+-----+
|code|golf|going|
+----+----+-----+

而且,J缺少哈希类型,因此它最接近的是两列项目表,例如框式字符串。如果那是不可接受的,并且我必须默认为键值格式,则可以将输出重新格式化为此格式,共67个字符

;@|.@,@((<&>',:'),."1,.~~.@,[:(#~1-1({.\e."_1]\.){:"1)@;(<,.<\)&.>)

爆炸解释:

(,.~~.@,[:(#~1-1({.\e."_1]\.){."1)@;(<\,.<)&.>) NB. unambiguous prefixes
                                    (     )&.>  NB. for each string:
                                     <\         NB.   take all prefixes
                                       ,.<      NB.   pair each with string
        [:                         ;            NB. gather up "partial" hashes
          (#~1-                  )@             NB. remove those rows where:
               1({.\        ){."1               NB.   each key
                    e."_1                       NB.   is an element of
               1(        ]\.){."1               NB.   the rest of the keys
 ,.~                                            NB. hash each word to itself
       ,                                        NB. add these rows to hash
    ~.@                                         NB. remove duplicate rows

例子:

   (,.~~.@,[:(#~1-1({.\e."_1]\.){."1)@;(<\,.<)&.>) 'pie';'pier';'pierre'
+------+------+
|pie   |pie   |
+------+------+
|pier  |pier  |
+------+------+
|pierre|pierre|
+------+------+
|pierr |pierre|
+------+------+
   NB. 1-char words have to be made into lists with ,
   (,.~~.@,[:(#~1-1({.\e."_1]\.){."1)@;(<\,.<)&.>) (,'a');'dog'
+---+---+
|a  |a  |
+---+---+
|dog|dog|
+---+---+
|d  |dog|
+---+---+
|do |dog|
+---+---+
   NB. "key:value," format, reversed order to save chars
   ;@|.@,@((<&>',:'),."1,.~~.@,[:(#~1-1({.\e."_1]\.){:"1)@;(<,.<\)&.>) 'code';'golf';'going'
goin:going,goi:going,gol:golf,cod:code,co:code,c:code,going:going,golf:golf,code:code,

2

哈斯克尔 96 87

import Data.List
i=inits
f a=a>>= \x->[(y,x)|y<-i x,y/="",y`notElem`(a>>=i)\\i x||y==x]

非高尔夫版本:

 import Data.List
 f a = concatMap (\x ->
     [(y, x) |
      y <- inits x,
      y /= "",
      y `notElem` concatMap inits a \\ inits x || y == x]
     ) a

例:

> f ["pi","pier","pierre"]
[("pi","pi"),("pier","pier"),("pierr","pierre"),("pierre","pierre")]

我使用了该inits函数,该函数查找列表/字符串的所有前缀。它算作作弊吗?


1
您可以替换concatMap通过(=<<),这是在前奏。为您节省10个字符。
Rhymoid

@Rhymoid谢​​谢。我删除了,concatMap但不能保存超过9个字符。
lortabac 2014年

哦,等等,你是对的。Haskell认为>>=\ 是单个词位。抱歉...
Rhymoid 2014年

2

的Python 3(97)

c=','
S=c+input()
for w in S.split(c):
 e=w
 while e:e<w<w*S.count(c+e)or print(e+':'+w);e=e[:-1]

我们遍历输入中每个单词的前缀,如果相应的前缀/单词对恰好出现一次或出现在整个单词中,则将其打印出来。我们仅利用满足以下条件之一的短路行为or(并print作为一种功能)来进行打印。

while循环反复切断最后一个字符创建短前缀,终止空字符串遗体时。这是我们唯一索引或切片任何内容的时间。

我们e通过在原始逗号分隔的输入字符串中S搜索substrings 来计算输入中前缀的出现次数','+e。我们事先将逗号放在输入字符串前。此加法会在we时产生一个额外的空字符串元素split,但这没有效果,因为它没有非空子字符串。

为了检查子字符串e是整个单词的情况w,我们使用字符串比较运算符对它们进行比较。按字典顺序比较,因此较短的前缀较小。如果e==w或,则双重比较失败S.count(c+e)<2

如果e,w允许以表格形式打印输出,我会改写e+c+w来保存一个字符。

归功于undergroundmonorail,我从我的总体代码结构中得出了答案


(e<w)*S.count(c+e)>1可以打高尔夫球以e<w<w*S.count(c+e)保存2个字符。
isaacg

@isaacg谢谢!我添加了您的优化。
xnor

1

红宝石114

def f(l);h={};l.each{|w|w.size.times{|i|k=w[0..i];h[k]=h[k]&&0||w}};h.delete_if{|k,v|v==0};l.each{|w|h[w]=w};h end

取消高尔夫:

def f(list)
  hash = {}
  list.each do |word|
    word.size.times do |i|
      key = word[0..i]
      h[key] = (hash[key] && 0) || word
    end
  end
  hash.delete_if{|key, value| v==0}
  list.each{|word| hash[word] = word}
  hash 
end

1

k4(70)

没有特别打高尔夫球;我相信它可能会更短

与J impl非常相似。上面我认为-基本上只是收集所有(正确)前缀,再次从前缀中删除单词(以处理"car"/ "carpet"case),将它们分组为对等类,仅用一个元素选择这些类,将它们从列表中减少为字符串,并将映射从字符串添加到自身。

f:{(x!x),*:'{(&1=#:'x)#x}{x@=y@:&~y in x}.,/'+{1_'(c#,x;(!c:#x)#\:x)}'x}

一些测试用例

请注意,在k/中q,字符串是字符列表,因此仅需使用一元,函数将仅包含单个字符的字符串标记为一;&mmwrt仅包含单个字符串的字符串列表

这些使用qshow功能(对于某些数据结构具有内置格式),以使结果更易读:

  .q.show f("code";"golf";"going")
"code" | "code"
"golf" | "golf"
"going"| "going"
,"c"   | "code"
"co"   | "code"
"cod"  | "code"
"gol"  | "golf"
"goi"  | "going"
"goin" | "going"
  .q.show f@,"pie"
"pie"| "pie"
,"p" | "pie"
"pi" | "pie"
  .q.show f("pie";"pier";"pierre")
"pie"   | "pie"
"pier"  | "pier"
"pierre"| "pierre"
"pierr" | "pierre"
  .q.show f(,"a";"dog")
,"a" | ,"a"
"dog"| "dog"
,"d" | "dog"
"do" | "dog"
  .q.show f("car";"carpet")
"car"   | "car"
"carpet"| "carpet"
"carp"  | "carpet"
"carpe" | "carpet"

1

的JavaScript的-212

w=prompt(o=[]).split(",");w.map(function(k,l){for(i=0;++i<k.length;){p=k.slice(0,i);if(w.filter(function(r,t){return t!=l}).every(function(r){return r.indexOf(p)}))o.push(p+":"+k)}o.push(k+":"+k)});console.log(o)

最初的高尔夫。

输入:

code,golf,going

输出:

["c:code", "co:code", "cod:code", "code:code", "gol:golf", "golf:golf", "goi:going", "goin:going", "going:going"]


1

Perl,93 77

带有换行符和缩进以提高可读性:

sub f{
    (map{
        $h{$x}=[($x=$`.$&,$_)x!$h{$x}]while/./g;
        $_,$_
    }@_),map@$_,values%h
}

太迟了,太长了,但是我很高兴它最终低于100。函数返回一个可以分配给哈希变量的列表:

%h = f(qw/code golf going pie pier pierre/);
print "$_ $h{$_}\n" for sort keys %h;

perl prefix.pl
c code
co code
cod code
code code
goi going
goin going
going going
gol golf
golf golf
pie pie
pier pier
pierr pierre
pierre pierre

实际上,返回列表尚未过滤-散列构造即在其分配即外部函数完成时完成。如果不够干净/不够合理,请加3进行计数并将函数内容放在花括号中,+然后加上前缀-然后函数返回“ true”哈希引用。


1

问:44个字节

{x!p@'(?0,&:)'p in\:&1=#:'=,/p:`$(-1_)\'$x}

笔记

  • Q语言有一个内部命名为K4的内核(用于此答案和该问题的另一个先前答案)

  • 要测试代码,请下载解释器(kx.com,免费用于非商业用途,支持Windows,Linux和Mac)

口译员接受两种语法:

  • 冗长(更易读的名称,mo子和diad的不同名称,更多的库,等等)。加载带有q扩展名的源文件或交互式解释器

  • 紧凑(功能性内核,一个字母运算符,两个字母都使用monad / diad的相同字母,...)。加载带有k扩展名的源文件,或以k模式加载交互式解释器(在提示符写入\)。必须在此模式下测试代码

该代码定义了一个lambda(匿名函数)。要给函数命名,我们需要前缀名称:(ex f:{..}),因此需要46个字节

测试

(假设命名函数:否则用f代替代码​​)

f `code`golf`going

`code`golf`going!(`code`cod`co`c;`golf`gol;`going`goin`goi)

返回字典(语法键!值)。键是符号列表(`symb`symb ..),其值是符号列表的列表。如果我们在交互式解释器上执行语句,我们将有一个更方便的表示形式(每个键和关联值在不同的行)

code | `code`cod`co`c
golf | `golf`gol
going| `going`goin`goi

说明

x 是lambda的隐式参数

$x 将符号列表转换为字符串列表

(-1_)\ 遍历符号列表的每个元素

(按每个字符串的读法计算前缀(在eat迭代中删除字符串的最后一个字符(-1_),直到空字符串为止)

$ 再次转换为符号列表(所有前缀的列表)

p: 并分配给p

,/ 光栅化所有(连接并创建一个一级结构)

= 分类->对于每个唯一前缀,将对应的单词关联

#:' 计算长度(与每个前缀关联的单词数)

1= 如果length = 1(明确),则为true,否则为false

& 其中->真实元素的索引

p in\: 确定所有前缀是否在明确前缀中

(..)' 将(..)应用于右边的每个值(明确的前缀)

?0,&: ->截然不同的0串联在哪里(以应付单词作为其前缀)

p@ 将索引转换为符号

x!.. 构造一个以x(单词)为键,..作为值的字典

读为:

  • 构造并返回以单词为键和值的字典。

  • ...在不同位置0(所有字)和明确前缀处的索引值

  • ...明确地计算为仅出现在一个单词上的前缀(与每个符号关联的单词列表的长度为1)

  • ...列出了将所有唯一符号与相应单词分类的结果

  • ...通过重复删除每个单词的最后一个字符来计算的前缀


1

PHP 7.0,67个字节(挑战提出后)

for(;a&$c=$s[++$k]??($s=$argv[++$i])[$k=+$t=!1];)echo$t.=$c,":$s,";

从命令行参数获取输入;打印尾随逗号;与运行-nr

对于较新的PHP,请添加一个字节:替换&a""<

对于较旧的PHP,请使用以下70个字节:

PHP,70个字节

for(;a&$s=$argv[++$i];)for($k=+$t="";a&$c=$s[$k++];)echo$t.=$c,":$s,";

1

Brachylog,23个字节

∋Xa₀Y;?↔⟨∋a₀⟩ᶜ1∧Y;X|∋gj

在线尝试!

通过输入变量将输入作为列表,并通过输出变量生成对列表[key, value]。尽管不是TIO上的标头通过使用获取完整列表(而不是)来隐藏它,但不是另一个输入字符串前缀的任何输入字符串都将作为其自身的前缀生成两次

 X                         X
∋                          is an element of
                           the input variable
    Y                      and Y
  a₀                       is a prefix of
 X                         X.
             ᶜ             The number of ways in which
        ⟨∋  ⟩              an element can be selected from
     ;?↔⟨   ⟩              the input variable
    Y; ↔⟨ a₀⟩              such that it has Y as a prefix
              1            is equal to 1.
               ∧Y          Y is not necessarily 1,
                   |       and the output variable
                Y;X        is the list [Y, X].
                   |       If every choice from the first rule has been taken already,
                           the output variable is
                    ∋      an element of
                   |       the input variable
                     gj    paired with itself.

如果输出中的重复项不被允许,请添加三个字节来包装整个内容{}ᵘ,除非有某种更短的方法可以排除某种形式为其自身的前缀,或者在没有额外规则的情况下生成每个必要的输出对∋gj
不相关的字符串,



0

巨蟒(127)

因此,我无法评论@undergroundmonorail,但我认为采用字典方法会更好?我敢肯定,通过一些列表/字典的理解,它也可以大大减少,但不能使其与字典中的内容配合使用。

i=raw_input().split(",")
d = {}
for x in i:
    for c in range(1,len(x)+1):
        if x[:c] in d:
            del d[x[:c]]
        else:
            d[x[:c]]=x
print d

印刷品将输出无序的字典。

编辑:啊,我错过了汽车:汽车/汽车:地毯的标准。也许要长度检查?


也许我错过了一些东西,但是这似乎在每次遇到前缀条目时都会交替添加和删除,所以如果出现3个单词,就不会出现模棱两可的前缀吗?
xnor 2014年

0

Groovy-212个字符

打高尔夫球:

c="collectEntries";f="findAll";def g={def h=[:].withDefault{[]};it.each{def w->w.size().times{ h[w[0..it]] << w}};(h."$f"{k,v->v.size()==1}."$c"{k,v->[k,v[0]]}).plus(h."$f"{k,v->v.contains(k)}."$c"{k,v->[k,k]})}

示例输出:

println g(["code","golf","going"])

[c:code, co:code, cod:code, code:code, gol:golf, golf:golf, goi:going, goin:going, going:going]

取消高尔夫:

def g = { def list ->
    def hash = [:].withDefault{[]}
    list.each {
        def word -> word.size().times{ hash[word[0..it]] << word }
    }

    def map = hash.findAll{ k,v -> v.size() == 1 }.collectEntries{ k,v -> [k,v[0]] }
    map.plus(hash.findAll{ k,v -> v.contains(k) }.collectEntries{ k,v -> [k,k] }
    map
}


0

Zsh,95个字节

local -A m
for w;{m[$w]=$w;x=
for c (${(s::)w})x+=$c&&[ ${(M)@:#$x*} = $w ]&&m[$x]=$w
}
local m

在线尝试!

在Bash / Zsh中“返回”关联数组的唯一方法是不使用local关键字声明它,然后在父作用域中访问它。这将节省一个字节。但是,通常不赞成通过变量进行I / O操作,因此我们将打印数组定义。

local -A m                          # declare m as associative
                                    # "local" is shorter than "typeset"/"declare"
for w;{                             # for each word
    m[$w]=$w                        # the word is a prefix of itself
    x=                              # ensure x is empty
    for c (${(s::)w})               # for each character in the word
        x+=$c &&                    # append to x (building a prefix
          [ ${(M)@:#$x*} = $w ] &&  # if the only match is the word itself:
          m[$x]=$w                  # ... then x is a prefix of w
}
local m                             # print m

0

红宝石,84字节

只是注意到已经有一个现有的Ruby解决方案,哦。这基本上是对旧解决方案的改进,它以一种更智能的方式选择了前缀(消除了将每个单词作为“前缀”添加到末尾的需要),并在将前缀添加到哈希之前对前缀进行计数以检查唯一性,而不是使用覆盖值如果有重复项,则为虚拟对象,然后擦除该条目。

->w{h={};w.map{|e|(1..e.size).map{|i|w.count{|d|d[0,i]==e[0,i]}<2?h[e[0,i]]=e:0}};h}

在线尝试!

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.