缩写数组


26

目标:

给定一个字符串数组,为每个字符串创建缩写版本。

规格:

对于此挑战,缩写是字符串的前N个字符。对于字符串abcaababc都是有效的缩写,而bcac则不是。

给定一个字符串数组,我们想找到最短的缩写集,这样在给定输入和任何缩写的情况下,您可以确定缩写所指的输入项。

例:

输入: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

从第一个字符串开始,我们一直在处理字符串。

  • 星期一只是带有的项目字符串M,因此,最短的缩写是M

  • 星期二从开始T,星期四也是如此。这意味着我们尝试使用字符串TU。由于没有其他字符串以此开头,因此我们使用TU

  • 星期三是W,星期四是Th,星期五是F

更多示例:

Input: "one,two,three,four,five,six,seven"
Output: "o,tw,th,fo,fi,si,se"

Input: "red,orange,yellow,green,blue,purple"
Output: "r,o,y,g,b,p"

Input: "a,ab,abc"
Output: Not valid! No abbreviation for `a` that doesn't apply to the other items.

笔记:

  • 您可以通过任何合理的方式进行输入和输出。

  • 您可以假设输入将始终是有效的字符串数组。

  • 您可以假定总会有一个解决方案,这与上一个测试用例不同。

  • 字符串仅包含可打印的ASCII(或编码中的可打印字符)

  • 这是代码高尔夫,所以最少的字节会赢!


相关:123
SP3000


2
我不认为这是其中任何一个的重复(尽管它们都非常相似)。实际上,我认为这可能是四个挑战中最大的挑战。其他的都有变种,这使它们不必要地变得复杂。

2
大小写重要吗?特别是,您的工作日示例U在星期二使用大写字母,但h在星期四使用小写字母。
布赖恩J

1
@Mego除非主持人将其标记为非重复,否则不要编辑我的帖子
朱利安·拉希尼特

Answers:


10

视网膜,29字节

!ms`^(.+?)(?!.+^\1)(?<!^\1.+)

输入和输出是换行符分隔的字符串列表。

在线尝试!(为方便起见,测试套件带有逗号分隔。)

说明

这只是将所有前缀与单个正则表达式匹配,并打印它们(!)。ms是使^匹配行开始和.换行符匹配的常用正则表达式修饰符。

^(.+?)      # Match the shortest possible prefix of a line and capture
            # it in group 1.
(?!.+^\1)   # Make sure that this prefix does not show up in a line after
            # the current one.
(?<!^\1.+)  # Make sure that this prefix does not show up in a line before
            # the current one.

10

Python 2中87 86个字节

lambda a:[b[:min(i for i in range(len(b))if sum(s[:i]==b[:i]for s in a)<2)]for b in a]

在线尝试!


lambda a:[[b[:i]for i in range(len(b))if sum(s[:i]==b[:i]for s in a)<2][0]for b in a]为85个字节
Curtis Bechtel

替换len(b)为会4**8节省2个字节,并假设字符串不得超过65536个字符
Curtis Bechtel

8

JavaScript(ES6),81 78 74 70字节

将输入作为字符串数组。

a=>a.map(s=>[...s].reduce((y,c)=>a.some(x=>x!=s&!x.indexOf(y))?y+c:y))

格式化和评论

a =>                          // given an array of strings 'a'
  a.map(s =>                  // for each string 's' in 'a':
    [...s].reduce((y, c) =>   //   starting with 'y' = first character of 's',
                              //   for each subsequent character 'c' of 's':
      a.some(x =>             //     if we find a string 'x' in 'a' such that:
        x != s &              //       - 'x' is different from 's'
        !x.indexOf(y)         //       - and 'y' appears at the beginning of 'x'
      ) ?                     //     then:
        y + c                 //       append 'c' to 'y'
      :                       //     else:
        y                     //       keep 'y' unchanged
    )                         //   end of reduce(): returns the correct prefix
  )                           // end of map()

测试用例


1
也是70个,但绝对不一样:codegolf.stackexchange.com/a/113270/32091
Qwertiy

为+1 reduce
尼尔

6

果冻,14字节

;\w@þ=1Si1⁸ḣð€

在线尝试!

怎么运行的

;\w@þ=1Si1⁸ḣð€  Monadic link. Argument: A (string array)

            ð   Collect all links to the left into a chain (arity unknown) and
                begin a dyadic chain.
             €  Map the previous chain over A. The current chain is dyadic and the
                mapped one inherits its arity. Thus, the right will be A for all
                invocations, while the left argument will iterate over A.
                For each string s in A, the following happens.
;\                Cumulative reduce by concatenation; yield all prefixes of s.
  w@þ             Window index swapped table; for each string t in A and each
                  prefix p of s, find the index of the substring t in p.
                  The first index is 1; 0 means not found.
     =1           Compare the indices with 1, returning 1 iff t begins with p.
       S          Sum the Booleans across columns, counting the number of strings
                  in A that begin with a given prefix.
        i1        Find the first index of 1, the shortest prefix that is unique
                  across all strings in A.
          ⁸       Head; truncate s to the computed length.

6

Haskell,48个字节

[_]#x=""
a#(c:y)=c:[z|d:z<-a,c==d]#y
f=map=<<(#)

在线尝试!

  • f是主要功能,获取Strings 的列表并返回a String。它的定义是的单子快捷方式f a=map (a#) a
  • a#x查看字符串x和列表,a并尝试查找其中x唯一的最短前缀a。如果a只有一个元素,则使用空字符串。如果a还不是单个元素,则将的第一个字符切掉x,过滤并切掉a以相同字符开始的元素,然后递归。

4

Mathematica,64个字节

#&@@@StringCases[#,Shortest@x__/;Tr@Boole@StringStartsQ[#,x]<2]&

3

果冻14 12字节

ḣ€JṙLḶ$ḟ/€Ḣ€

在线尝试!

怎么运行的

ḣ€JṙLḶ$ḟ/€Ḣ€  Main link. Argument: A (string array)

  J           Yield the 1-based indices of A, i.e., [1, ..., len(A)].
ḣ€            Head each; for each string s in A, take the first 1, ..., and len(A) 
              characters. This builds the 2D array of prefixes of all strings in A.
    LḶ$       Length-unlength; yield [0, ..., len(A)-1].
   ṙ          Rotate the 2D array 0, ..., and len(A)-1 units to the left.
       ḟ/€    Reduce filterfalse each; for each rotation, remove all prefixes from
              the first set that also occur in later sets.
          Ḣ€  Head each; for each rotation, keep only the shortest unique prefix.

只是想知道,为什么在这里有2个答案?我都喜欢它们,但我只是想知道为什么您在这里有两个果冻答案。:)
HyperNeutrino

如果我有两种类似的竞争方法但又有足够不同的方法,我通常将它们分别张贴在答案中。
丹尼斯

好点子。是的,我只是想知道。:)这是一个好主意;我通常不止一种方法:P
HyperNeutrino

2

C ++ 11(MinGW),198个字节

#import<list>
#import<iostream>
f(std::list<std::string>l){int i,m;for(auto s:l){for(i=0,m=1;++i<s.length();)for(auto t:l)if(t!=s&&t.substr(0,i)==s.substr(0,i))m=i+1;std::cout<<s.substr(0,m)<<" ";}}

致电:

int main()
{
    f({"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"});
}

void在该函数之前添加标识符也应使其在其他编译器上进行编译,从而在长度上增加5个字节。


void f...不幸的是,应该为,否则将无法正常工作... + 5个字节。据我所知,函数需要使用C ++中的类型说明符
Xcoder先生17年

除此之外,出色的方法!在C / C ++中打高尔夫球可能会很痛苦
Xcoder先生17年

@ Mr.Xcoder不过,它确实可以在我使用的MinGW编译器上进行编译。因此,它要么是编译器扩展,要么是未定义的行为。
Steadybox

我认为这与编译器扩展有关,在GCC上不起作用...
Xcoder先生17年

1
只要有一个可以在其中运行代码的环境,它
Undergroundmonorail

2

Javascript ES6,70个字符

s=>(s+'#'+s).replace(/(\w+?)(\w*)(?=(\W(?!\1(?!\2))\w+)+$)|#.+/g,"$1")

f=s=>(s+'#'+s).replace(/(\w+?)(\w*)(?=(\W(?!\1(?!\2))\w+)+$)|#.+/g,"$1")

console.log(f("one,two,three,four,five,six,seven")==="o,tw,th,fo,fi,si,se")
console.log(f("red,orange,yellow,green,blue,purple")==="r,o,y,g,b,p")
console.log(f("one,two,three,four,five,six,seven".split`,`)==="o,tw,th,fo,fi,si,se")
console.log(f("red,orange,yellow,green,blue,purple".split`,`)==="r,o,y,g,b,p")


2

PHP,131120119118字节

感谢@Jörg的支持preg_grep

for(;a&$s=$argv[++$k];$i=+$t=!print"$t
")for(;a&$s[$i]&&1<count(preg_grep("(^".preg_quote($t.=$s[$i++]).")",$argv)););

从命令行参数获取输入;每行打印结果一行。
运行-nr在线尝试

  • 如果输入包含以开头的任何内容,则可能会失败-
    15字节来修正:替换所述第二$argvarray_slice($argv,1)
  • 在PHP 7.1中产生警告;替换a&""<(+1字节)以修复。
  • 如果输入不包含正则表达式特殊字符,则为-12个字节:
    &($t.=$c)之前插入&&并替换". preg_quote($t.=$c)."$t

分解

for(;a&$s=$argv[++$k];      # loop $s through arguments
    $i=+$t=!                # 3. reset $i and $t to empty
    print"$t\n")            # 2. print abbreviation
    for(;a&($c=$s[$i++])    # 1. loop $c through characters
        &&1<count(              # 3. if count==1, break loop
            preg_grep("(^"      # 2. find matching arguments
                . preg_quote(
                $t.=$c          # 1. append $c to abbreviation
            ).")",$argv)
        );
    );

非正则表达式版本131130字节

for($a=$argv;a&$s=$a[++$k];$i=+$t=!print"$t
")for($n=1;$n&&a&$c=$s[$i++];)for($n=$m=1,$t.=$c;a&$u=$a[$m++];)$n-=0===strpos($u,$t);

a&""<(+2个字节)替换第一个和最后一个以修复PHP 7.1。

分解

for($a=$argv;a&$s=$a[++$k];     # loop through arguments
    $i=+$t=!print"$t\n")            # 2. print abbreviation, reset $i and $t to empty
    for($n=1;$n&&a&$c=$s[$i++];)    # 1. loop through characters while $n<>0
        for($n=$m=1,                    # reset $n and $m to 1
            $t.=$c;                     # append current character to prefix
            a&$u=$a[$m++];              # loop through arguments:
        )$n-=0===strpos($u,$t);         # -$n = number of matching strings -1

完全没有意思的注释:
strstr($u,$t)==$u并且0===strpos($u,$t)具有相同的长度和相同的结果。


使用实际的换行符(0x0A)代替\n,它将节省一个字节;)。
黑洞

@Blackhole谢谢;这次我忘记了这一点。
泰特斯

1

PHP,127字节

不适用于无效数组

<?foreach($a=$_GET as$k=>$v)for($i=0,$c=2,$s="";$c>1;$r[$k]=$s)$c=count(preg_grep("_^".($s.=$v[$i++])._,$a));echo join(",",$r);

PHP,132字节

<?foreach($a=$_GET as$v)for($i=0,$s="";a&$v[$i];)if(count(preg_grep("_^".($s.=$v[$i++])._,$a))==1){$r[]=$s;break;}echo join(",",$r);

在线版本

151字节支持特殊字符

<?foreach($a=$_GET as$v)for($i=0,$s="";a&$v[$i];)if(count(preg_grep("_^".preg_quote($s=substr($v,0,++$i),_)._,$a))==1){$r[]=$s;break;}echo join(",",$r);

PHP,140字节

<?foreach($a=$_GET as$k=>$v)for($i=0;a&$v[$i];)if(count(preg_grep("#^".($s=substr($v,0,++$i))."#",$a))==1){$r[]=$s;break;}echo join(",",$r);

如果输入包含正则表达式特殊字符,则此操作将失败。如果没有,我将拥有113个字节而不是131个字节。
泰特斯

@Titus在这种情况下,我可以添加一个preg_quote只作10个字节以上
约尔格Hülsermann

如果输入包含,也会失败0。但是您可以使用保存一个字节$i=+$s=""
泰特斯(Titus)

并且您可以删除这些count()-count()内容:保证输入有效(-21字节)。我想我可以解决这个问题并将其压缩到120个字节。$_GET是个好主意!
泰特斯

@Titus我还没有意识到只允许有效的数组。是的,如果字符串包含零,它会失败,但是这已经诞生了一个想法
约尔格Hülsermann

0

Clojure,118个字节

#(reduce(partial map(fn[a b](or a b)))(for[i(range 1e2)S[(for[c %](take i c))]](for[s S](if(=((frequencies S)s)1)s))))

这适用于最大长度为的前缀,1e2但是相同的字节数可以支持最大长度1e9i循环前缀的长度,S是length的子字符串序列i。最后一个for替换那些nil频繁出现的子字符串。减少会保留每个字符串的第一个非nil值,太糟糕了or不是一个函数,所以我不得不包装它。

实际上,这会返回字符列表,如((\M) (\T \u) (\W) (\T \h) (\F)),但我想这是可以接受的。Clojure的字符串很冗长,并且subs会抛出不StringIndexOutOfBoundsException一样的情况take

完整示例:

(def f #(reduce(partial map(fn[a b](or a b)))(for[i(range 1e2)S[(for[c %](take i c))]](for[s S](if(=((frequencies S)s)1)s)))))

(f ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"])
(f (re-seq #"[^,]+" "one,two,three,four,five,six,seven"))
(f (re-seq #"[^,]+" "red,orange,yellow,green,blue,purple"))

0

SQL(PostgreSQL 9.4风格),219字节

现在,最长的答案是:)我认为这甚至无法击败Java。我将尝试剃掉更多。希望摆脱嵌套查询之一,但不喜欢我的机会。
假定存在一个包含要处理的字符串的表。由于这是SQL,因此不能保证返回顺序与表顺序相同,在这种情况下不太可能。如果这是一个问题,我将删除。

SELECT R FROM(SELECT*,RANK()OVER(PARTITION BY A ORDER BY C,N)Z FROM(SELECT*,SUM(1)OVER(PARTITION BY R)C FROM(SELECT*FROM A JOIN LATERAL(select left(A,n)R,N FROM generate_series(1,length(A))S(n))L ON 1=1)X)Y)Z WHERE Z=1

SQL提琴
说明

  SELECT *
  FROM A 
    JOIN LATERAL(SELECT LEFT(A,n)R,N 
    FROM generate_series(1,length(A))S(n))L ON 1=1

最里面的查询使用generate_seriesLATERAL连接来为字符串创建行,行分成增加的长度,因此'one'变为'o','on','one'。返回中的字符数也保持不变。

SELECT 
  *,
  SUM(1)OVER(PARTITION BY R)C
FROM ( ... )X

然后,我们添加具有相同结果的记录数。例如,四个和五个中的“ f”有2,但是“ fo”和“ fi”每个都有一个。OVERSQL中的语句可能非常强大。 COUNT(*)将是通常的方式,但SUM(1)结果相同。

SELECT 
  *,
  RANK()OVER(PARTITION BY A ORDER BY C,N)Z
FROM ( ... )Y

然后,我们基于最少的重复和字符对每个输入的结果进行排名。 ROW_NUMBER也会在这里工作,但时间更长。

SELECT R FROM ( ... )Z WHERE Z=1;

最后,我们为每个单词选择最低的等级编号。


0

纯Bash,146字节

for i in $@;{ K=1;U=${i::1};((M++));L=;while [[ `for v in $@;{ ((L++));(($L!=$M))&&echo ${v::K}||:;}` =~ $U ]];do U=${i::K};((K++));done;echo $U;}

在线尝试!


0

APL(Dyalog),27字节

{⍵↑¨⍨1⍳⍨¨↓+/(↑,⍵)∘.(⊃⍷)⍵}

在线尝试!

{ 一个匿名函数,其中⍵表示参数...

∘.( 功能表

   第一个要素

   布尔值列表“左参数从右参数开始?”

) 正确的论据在哪里

 争论

( 左边的参数是

   由行组成的表

  ,/ 的前缀

  ¨ 每个

   论点

+/ 求和(计算使用该前缀的befin参数的数量)

 将表拆分为行列表

⍳⍨¨ 在每一个中,找到第一个的位置

1 一个(即仅带一个参数的第一个前缀)

↑¨⍨ 对于每个位置,从的相应元素中获取那么多字符

 论点

} 匿名函数的结尾


0

PowerShell中,151个 139字节

$x,$w=@(),$args[0];$w|%{$k=$_;$a='';foreach($l in [char[]]$k){$a+=$l;if($a-notin$x-and!($w|?{$_-ne$k-and$_-like"$a*"})){$x+=$a;break;}}};$x

感兴趣是否有更好的方法来做到这一点。必须使用foreach(超过|%)才能break在嵌套循环中执行而不标记它。

编辑:从AdmBorkBork 2高尔夫球


1
我没有直接检查代码,但是可以肯定的是,您可以使用-notin代替-not$x.contains($a)!($w...代替-not($w...保存一些字节,是吗?
AdmBorkBork

0

APL,26个字节

{⍵↑¨⍨1+⌈/+/¨∘.(∧\=∧≢)⍨↓↑⍵}

说明:

  • ↓↑⍵:填充每个字符串以匹配最长字符串的长度
  • ∘.(... )⍨:对于每个可能的字符串对,找到共享的前缀:
    • :数组不等式
    • :和
    • =:逐项相等
    • ∧\:and-scan(仅保留前导匹配项)
  • +/¨:对表中的每个向量求和,给出共享前缀的长度
  • ⌈/:在每一列中找到最大值
  • 1+:添加一个,给出保持每个字符串唯一所需的字符数
  • ⍵↑¨⍨:从每个字符串中提取那么多字符

测试:

      {⍵↑¨⍨1+⌈/+/¨∘.(∧\=∧≢)⍨↓↑⍵}'Monday' 'Tuesday' 'Wednesday' 'Thursday' 'Friday'
┌─┬──┬─┬──┬─┐
│M│Tu│W│Th│F│
└─┴──┴─┴──┴─┘
      {⍵↑¨⍨1+⌈/+/¨∘.(∧\=∧≢)⍨↓↑⍵}'one' 'two' 'three' 'four' 'five' 'six' 'seven'
┌─┬──┬──┬──┬──┬──┬──┐
│o│tw│th│fo│fi│si│se│
└─┴──┴──┴──┴──┴──┴──┘
      {⍵↑¨⍨1+⌈/+/¨∘.(∧\=∧≢)⍨↓↑⍵}'red' 'orange' 'yellow' 'green' 'blue' 'purple'
┌─┬─┬─┬─┬─┬─┐
│r│o│y│g│b│p│
└─┴─┴─┴─┴─┴─┘

0

Q,93个字节

{n:1;{$[any e:(,/)1<{(+/)i like x}each i:z#'x;[z+:1;y:?[e;z#'x;i];.z.s[x;y;z]];y]}[x;n#'x;n]}

递归求解,将字符串作为输入,每次递归都获取每个字符串的前n个元素。如果这些元素中的任何一个都不唯一,则将其替换为前n + 1个元素。

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.