Menyingkat sebuah array


26

Tujuan:

Diberikan array string, buat versi singkat dari setiap string.

Spesifikasi:

Untuk tantangan ini, singkatan adalah karakter N pertama dari sebuah string. Untuk string abc: a,, abdan abcsemua singkatan yang valid, sementara bc, dan actidak.

Diberikan serangkaian string, kami ingin menemukan kumpulan singkatan terpendek, sehingga memberikan input dan singkatan apa pun, Anda bisa menentukan item input mana yang mengacu pada singkatan tersebut.

Contoh:

Memasukkan: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

Kami bekerja melalui string yang dimulai dengan yang pertama.

  • Monday hanya string item dengan M, jadi singkatan yang sesingkat mungkin adalah M.

  • Selasa dimulai dengan T, tetapi begitu juga Kamis. Ini artinya kita mencoba string TU. Karena tidak ada string lain yang dimulai dengan itu, kami menggunakan TU.

  • Rabu adalah W, Kamis Th, dan Jumat F.

Lebih banyak contoh:

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.

Catatan:

  • Anda membuat input dan output dengan cara yang masuk akal.

  • Anda dapat mengasumsikan bahwa input akan selalu berupa array string yang valid.

  • Anda dapat mengasumsikan bahwa akan selalu ada solusi, tidak seperti pada test case terakhir.

  • String hanya akan terdiri dari ASCII yang dapat dicetak (atau karakter yang dapat dicetak dalam penyandian Anda)

  • Ini kode golf, byte paling sedikit menang!


Terkait: 1 , 2 , 3
Sp3000

5
Kemungkinan duplikat dari Golf Down the PPCG Usernames
Okx

2
Saya tidak berpikir itu adalah duplikat dari semua itu (walaupun mereka semua cukup mirip). Sebenarnya, saya pikir ini mungkin tantangan terbaik di antara empat; yang lain semuanya memiliki varian yang membuatnya menjadi rumit.

2
Apakah case itu penting? Secara khusus, contoh hari kerja Anda menggunakan modal Uuntuk hari Selasa, tetapi huruf kecil huntuk hari Kamis.
Brian J

1
@Mego Jangan edit posting saya kecuali moderator akan menandainya bukan duplikat
Julian Lachniet

Jawaban:


10

Retina , 29 byte

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

Input dan output adalah daftar string yang dipisahkan oleh linefeed.

Cobalah online! (Test suite dengan pemisahan koma untuk kenyamanan.)

Penjelasan

Ini hanya cocok dengan semua awalan dengan satu regex dan mencetaknya ( !). mdan smerupakan pengubah regex yang biasa untuk membuat ^awal .baris pertandingan dan mencocokkan baris baris.

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

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]

Cobalah online!


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]untuk 85 byte
Curtis Bechtel

mengganti len(b)dengan 4**8menyimpan 2 byte lebih banyak, dengan asumsi string tidak boleh lebih dari 65536 karakter
Curtis Bechtel

8

JavaScript (ES6), 81 78 74 70 byte

Mengambil input sebagai array string.

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

Diformat dan dikomentari

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

Uji kasus


1
70 juga, tetapi benar-benar lainnya: codegolf.stackexchange.com/a/113270/32091
Qwertiy

+1 untuk reduce.
Neil

6

Jelly , 14 byte

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

Cobalah online!

Bagaimana itu bekerja

;\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 byte

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

Cobalah online!

  • fadalah fungsi utama, mengambil daftar Strings dan mengembalikan a String. Definisinya adalah jalan pintas monadik untuk f a=map (a#) a.
  • a#xmelihat string xdan daftar adan mencoba menemukan awalan terpendek xyang unik di a. Jika amemiliki elemen tunggal, cukup gunakan string kosong. Jika abelum menjadi elemen tunggal, potong karakter pertama x, filter dan potong elemen adimulai dengan karakter yang sama, lalu ulangi.

4

Mathematica, 64 byte

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

3

Jelly , 14 12 byte

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

Cobalah online!

Bagaimana itu bekerja

ḣ€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.

Hanya ingin tahu, mengapa Anda punya 2 jawaban di sini? Saya suka keduanya tetapi saya hanya ingin tahu mengapa Anda memiliki dua jawaban Jelly di sini. :)
HyperNeutrino

Jika saya memiliki dua pendekatan kompetitif yang sama tetapi pendekatan yang cukup berbeda, saya biasanya mempostingnya dalam jawaban yang terpisah.
Dennis

Poin bagus. Ya, saya hanya ingin tahu. :) Itu ide yang bagus; Saya biasanya tidak memiliki lebih dari satu pendekatan: P
HyperNeutrino

2

C ++ 11 (MinGW), 198 byte

#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)<<" ";}}

Telepon dengan:

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

Menambahkan voididentifier sebelum fungsi harus membuatnya dikompilasi pada kompiler lain juga, sehingga menambah panjang 5 byte.


Seharusnya void f..., itu tidak berfungsi sebaliknya ... + 5 byte, sayangnya. Fungsi, sejauh yang saya tahu, perlu jenis
penentu

Selain itu, pendekatan yang luar biasa!
Bermain

@ Mr.Xcoder Mengompilasi pada kompiler MinGW yang saya gunakan. Jadi ekstensi kompiler atau perilaku tidak terdefinisi.
Steadybox

Saya pikir ini tentang ekstensi kompiler, pada GCC tidak berfungsi ...
Tn. Xcoder

1
Selama ada lingkungan di mana kodenya bekerja, itu valid
undergroundmonorail

2

Javascript ES6, 70 karakter

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 byte

Terima kasih @ Jorg untuk 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)););

mengambil input dari argumen baris perintah; hasil cetak masing-masing satu baris.
Jalankan dengan -nratau coba online .

  • mungkin gagal jika input berisi sesuatu yang dimulai dengan -.
    +15 byte untuk diperbaiki: ganti yang kedua $argvdengan array_slice($argv,1).
  • menghasilkan peringatan di PHP 7.1; ganti a&dengan ""<(+1 byte) untuk memperbaikinya.
  • -12 byte jika input tidak mengandung karakter khusus regex:
    Masukkan &($t.=$c)sebelum &&dan ganti ". preg_quote($t.=$c)."dengan $t.

kerusakan

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

versi non-regex, 131 130 byte

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

Ganti yang pertama dan yang terakhir a&dengan ""<(+2 byte) untuk diperbaiki untuk PHP 7.1.

kerusakan

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

catatan sama sekali tidak menarik:
strstr($u,$t)==$udan 0===strpos($u,$t)memiliki panjang yang sama dan hasil yang sama.


Gunakan karakter baris baru yang sebenarnya (0x0A ) alih-alih \n, itu akan menghemat satu byte;).
Blackhole

@ Blackhole Terima kasih; Saya lupa tentang itu kali ini.
Titus

1

PHP, 127 Bytes

berfungsi tidak dengan array yang tidak valid

<?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 Bytes

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

Versi Online

151 Bytes mendukung karakter khusus

<?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 Bytes

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

Ini akan gagal jika input berisi karakter khusus regex. Saya akan memiliki 113 byte, bukan 131 jika tidak.
Titus

@Titus Dalam hal ini saya bisa menambahkan preg_quoteMake hanya 10 Bytes lagi
Jörg Hülsermann

Ini juga akan gagal jika input berisi 0. Tetapi Anda dapat menyimpan satu byte dengan $i=+$s="".
Titus

dan Anda dapat menghapus count()-count()barang: input dijamin valid (-21 byte). Saya pikir saya bisa memperbaiki dan golf ini hingga 120 byte. $_GETitu ide yang bagus!
Titus

@ Titus Saya belum menyadari bahwa hanya array yang valid yang diperbolehkan. Ya itu akan gagal jika string mengandung nol tetapi ini telah melahirkan ide
Jörg Hülsermann

0

Clojure, 118 byte

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

Ini berfungsi pada awalan hingga panjang 1e2tetapi jumlah byte yang sama dapat mendukung hingga 1e9. ipanjang loop awalan, Sadalah urutan panjang substringi . Yang terakhir formenggantikan substring dengan nilyang terjadi lebih sering dari sekali. Pengurangan membuat nilai non-nil pertama untuk setiap string, sayang sekali orbukan fungsi jadi saya harus membungkusnya.

Ini sebenarnya mengembalikan daftar daftar karakter seperti ((\M) (\T \u) (\W) (\T \h) (\F)), tapi saya kira itu dapat diterima. Clojure cukup verbose dengan string, dansubs akan melempar StringIndexOutOfBoundsExceptiontidak seperti take.

Contoh lengkap:

(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 (rasa PostgreSQL 9.4), 219 byte

Sekarang untuk jawaban terlama :) Saya tidak berpikir ini bahkan bisa mengalahkan Java. Saya akan mencoba untuk mencukur lebih sedikit dari ini. Berharap untuk menyingkirkan salah satu kueri bersarang, tetapi tidak suka peluang saya.
Ini mengasumsikan bahwa ada tabel yang berisi string untuk dikerjakan. Karena ini adalah SQL, urutan pengembalian tidak dijamin sama dengan urutan tabel dan dalam hal ini tidak mungkin. Jika ini masalah, saya akan hapus.

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


Penjelasan SQL Fiddle

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

Kueri terdalam menggunakan generate_seriesdan LATERALbergabung untuk membuat baris untuk string yang dipisah menjadi panjang yang bertambah, jadi 'satu' menjadi 'o', 'on', 'one'. Jumlah karakter dalam pengembalian juga disimpan.

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

Kemudian kami menambahkan jumlah rekaman yang memiliki hasil yang sama. Misalnya 'f' dari empat dan lima memiliki 2, tetapi 'fo' dan 'fi' masing-masing memiliki satu. The OVERpernyataan SQL dapat cukup kuat. COUNT(*)akan menjadi cara yang biasa, tetapi SUM(1)memberikan hasil yang sama.

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

Kemudian kami memberi peringkat hasil untuk setiap input berdasarkan pada pengulangan dan karakter yang paling sedikit. ROW_NUMBERakan bekerja di sini juga, tetapi lebih lama.

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

Akhirnya kami memilih nomor peringkat terendah untuk setiap kata.


0

Bash Murni , 146 byte

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

Cobalah online!


0

APL (Dyalog) , 27 byte

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

Cobalah online!

{ fungsi anonim, di mana ⍵ mewakili argumen ...

∘.( tabel fungsi tempat fungsi tersebut

   elemen pertama dari

   daftar Boolean "argumen kiri dimulai di sini dalam argumen yang benar?"

) dimana argumen yang benar

 arguemts

( dan argumen kiri adalah

   sebuah tabel dengan baris yang terdiri dari

  ,/ awalan dari

  ¨ setiap

   argumen

+/ jumlah keseluruhan (menghitung berapa banyak argumen yang diakhiri dengan awalan ini)

 pisahkan tabel menjadi daftar baris

⍳⍨¨ di masing-masing, cari lokasi yang pertama

1 satu (yaitu awalan pertama yang hanya memimpin satu argumen)

↑¨⍨ untuk setiap lokasi, ambil banyak karakter dari elemen yang sesuai dari

 argumen

} akhir fungsi anonim


0

PowerShell, 151 139 byte

$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

Tertarik jika ada cara yang lebih baik untuk melakukan ini. Harus menggunakan foreach(lebih dari a |%) untuk dapat melakukan breakdalam loop bersarang tanpa label.

Sunting: 2 golf dari AdmBorkBork


1
Aku sudah tidak melalui kode secara langsung, tapi pasti Anda bisa menggunakan -notinbukannya -not$x.contains($a)dan !($w...bukan -not($w...untuk menghemat byte, ya?
AdmBorkBork

0

APL, 26 byte

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

Penjelasan:

  • ↓↑⍵: pad setiap string agar sesuai dengan panjang string terpanjang
  • ∘.(... )⍨: untuk setiap pasangan string yang mungkin, temukan awalan bersama:
    • : ketimpangan array
    • : dan
    • =: kesetaraan itemwise
    • ∧\: and-scan (hanya simpan yang terkemuka)
  • +/¨: jumlah masing-masing vektor dalam tabel, memberikan panjang awalan bersama
  • ⌈/: temukan nilai maksimum di setiap kolom
  • 1+: tambahkan satu, berikan jumlah karakter yang dibutuhkan untuk menjaga setiap string tetap unik
  • ⍵↑¨⍨: ambil banyak karakter dari setiap string

Uji:

      {⍵↑¨⍨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 byte

{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]}

Dipecahkan secara rekursif, mengambil string sebagai input, mendapatkan elemen pertama dari setiap string dengan setiap rekursi. Jika salah satu dari elemen-elemen itu tidak unik itu menggantikannya dengan elemen n + 1 pertama.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.