配列を短縮する


26

ゴール:

文字列の配列を指定して、各文字列の短縮バージョンを作成します。

仕様:

このチャレンジでは、略語は文字列の最初のN文字です。文字列の場合abcaab、およびabcすべての有効な略語があり、一方でbc、とacはありません。

文字列の配列が与えられた場合、入力と略語が与えられた場合に、略語が参照している入力の項目を判別できるように、略語の最短セットを見つけたいと思います。

例:

入力: ["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
私はそれがそれらのいずれかの複製だとは思わない(それらはすべてかなり似ているが)。実際、これはおそらく4つの中で最も良い挑戦だと思います。他のすべては、それらを不必要に複雑にするバリアントを持っています。

2
大文字小文字は重要ですか?特に、平日の例ではU火曜日に大文字を使用しますが、h木曜日には小文字を使用します。
ブライアンJ

1
司会者が重複していないとして、それをマークする場合を除き@Mego Doが私のポストを編集しない
ジュリアンLachniet

回答:


10

網膜、29バイト

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

入力と出力は、改行で区切られた文字列のリストです。

オンラインでお試しください!(便宜上、コンマ区切りのテストスイート。)

説明

これは、すべてのプレフィックスを単一の正規表現と単に照合し、それらを出力します(!)。mおよびsは、^一致する行の先頭と.一致する改行を作成するための通常の正規表現修飾子です。

^(.+?)      # 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.


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=<<(#)

オンラインでお試しください!

  • fStringsのリストを取得してを返すメイン関数Stringです。その定義はの単項ショートカットですf a=map (a#) a
  • a#xは、文字列xとリストaを見て、のx一意の最短プレフィックスを見つけようとしますa。場合はa、単一の要素を持っている、ちょうど空の文字列を使用します。aが単一の要素でない場合は、の最初の文字を切り取り、同じ文字xa始まる要素をフィルタリングして切り取り、その後再帰します。


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つの答えがあるのですか?私は両方とも好きですが、なぜここに2つのゼリーの答えがあるのか​​疑問に思っています。:)
HyperNeutrino

同様に競合する2つのアプローチがあるが、アプローチが十分に異なる場合、通常は別々の回答で投稿します。
デニス

いい視点ね。ええ、私はただ疑問に思っていました。:) それは良いアイデアです; 私は通常、複数のアプローチを持っていません: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

それに加えて、優れたアプローチ!C / C ++は、痛みを伴うことができるでゴルフ
氏Xcoder

@ Mr.Xcoderただし、私が使用しているMinGWコンパイラでコンパイルします。したがって、それはコンパイラの拡張機能または未定義の動作です。
-Steadybox

私は... GCCの上それは仕事をしない、それはコンパイラの拡張機能についてだと思う
氏Xcoder

1
コードが機能する環境がある限り、それは有効です
地下

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、131 120 119 118バイト

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

コマンドライン引数から入力を受け取ります。結果を1行ずつ出力します。
で実行する-nr、オンラインで試してください

  • 入力がで始まるものを含む場合、失敗する可能性があり-ます。
    修正する+15バイト:2番目$argvをで置き換えarray_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)
        );
    );

非正規表現バージョン、131 130バイト

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

PHP 7.1用に修正するには、最初と最後a&""<(+2バイト)に置き換えます。

壊す

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)==$u0===strpos($u,$t)同じ長さと同じ結果を持っています。


0x0A代わりに実際の改行文字()を使用して、\n1バイトを節約します;)。
ブラックホール

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

入力に正規表現の特殊文字が含まれている場合、これは失敗します。そうでなければ、131バイトではなく113バイトになります。
タイタス

この場合、@Titus私は追加することができますpreg_quote唯一の10バイトよりメイクを
イェルクHülsermann

入力にが含まれて0いる場合も失敗します。ただし、を使用して1バイトを保存できます$i=+$s=""
タイタス

そして、あなたはcount()-count()ものを取り除くことができます:入力は有効であることが保証されています(-21バイト)。これを120バイトまで修正してゴルフできると思います。$_GET良いアイデアでした!
タイタス

@Titus有効な配列のみが許可されていることに気付いていません。はい、文字列にゼロが含まれていると失敗しますが、これはアイデアを
生み出していた

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ますが、同じバイトカウントで最大をサポートでき1e9ます。iプレフィックスのループの長さはS、lengthの部分文字列のシーケンスですi。最後のfor部分文字列はnil、1回よりも頻繁に出現する部分文字列を置き換えます。リダクションは、各文字列の最初の非nil値を保持しますorが、機能が悪いので、それをラップする必要がありました。

これは実際にのような文字のリストのリストを返します((\M) (\T \u) (\W) (\T \h) (\F))が、私はそれが受け入れられると思います。Clojureは文字列では非常に冗長であり、とsubsStringIndexOutOfBoundsException異なりスローし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に勝ることさえないと思います。これからもう少し削ります。ネストされたクエリの1つを削除することを望んでいますが、私のチャンスが好きではありません。
これは、作業対象の文字列を含むテーブルがあることを前提としています。これは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

次に、同じ結果を持つレコードの数を追加します。たとえば、4と5の「f」には2がありますが、「fo」と「fi」にはそれぞれ1があります。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

APL(Dyalog)、27バイト

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

オンラインでお試しください!

{ 匿名関数。⍵は引数を表します...

∘.( 関数がある関数テーブル

   の最初の要素

   ブールリスト「左の引数は右の引数からここから始まる?」

) 正しい引数は

 議論

( そして左の引数は

   行で構成される表

  ,/ の接頭辞

  ¨ それぞれの

   引数

+/ 合計(このプレフィックスを使用して引数の数をカウントします)

 テーブルを行のリストに分割する

⍳⍨¨ それぞれで、最初の場所を見つける

1 one(つまり、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つ追加して、各文字列を一意に保つために必要な文字数を指定します
  • ⍵↑¨⍨:各文字列から多くの文字を取り出します

テスト:

      {⍵↑¨⍨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要素に置き換えます。

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