Fungsi Soundex

13

Tulis fungsi terpendek untuk menghasilkan kode American Soundex untuk nama keluarga yang hanya berisi huruf besar AZ. Fungsi Anda harus menghasilkan output yang konsisten dengan semua contoh halaman yang ditautkan (diberikan di bawah), meskipun tidak perlu dan tidak harus menghapus awalan. Tanda hubung dalam output adalah opsional. Selamat bersenang-senang!

Catatan: Anda tidak boleh menggunakan soundex()fungsi yang termasuk dalam PHP atau setara dalam bahasa pemrograman lain.

Contohnya:

WASHINGTON W-252
LEE L-000
GUTIERREZ G-362
PFISTER P-236 
JACKSON J-250 
TYMCZAK T-522
VANDEUSEN V-532
ASHCRAFT A-261
PleaseStand
sumber

Jawaban:

4

Perl, 143 150 karakter

sub f{$_="$_[0]000";/./;$t=$&;s/(?<=.)[HW]//g;s/[BFPV]+/1/g;s/[CGJKQSXZ]+/2/g;s/[DT]+/3/g;s/L+/4/g;s/[MN]+/5/g;s/R+/6/g;s/(?<=.)\D//g;/.(...)/;"$t$1"}

Solusi ini hanya berisi ekspresi reguler yang diterapkan satu demi satu. Sayangnya saya tidak menemukan representasi yang lebih pendek dengan loop jadi saya hard-kode semua panggilan ke dalam skrip.

Versi yang sama tetapi sedikit lebih mudah dibaca:

sub f{
  $_="$_[0]000";        # take first argument and append "000"
  /./;$t=$&;            # save first char to variable $t
  s/(?<=.)[HW]//g;      # remove and H or W but not the first one
  s/[BFPV]+/1/g;        # replace one or more BFPV by 1
  s/[CGJKQSXZ]+/2/g;    # replace one or more CGJKQSXZ by 2
  s/[DT]+/3/g;          # replace one or more DT by 3
  s/L+/4/g;             # replace one or more L by 4
  s/[MN]+/5/g;          # replace one or more MN by 5
  s/R+/6/g;             # replace one or more R by 6
  s/(?<=.)\D//g;        # remove and non-digit from the result but not the first char
  /.(...)/;"$t$1"       # take $t plus the characters 2 to 4 from result
}

Sunting 1: Sekarang solusinya ditulis dalam bentuk fungsi. Yang sebelumnya membaca / menulis dari / ke STDIN / STDOUT. Harganya tujuh karakter untuk mengatasi itu.

Howard
sumber
2

eTeX, 377.

\let\E\expandafter
\def\x#1;#2#3{\def\s##1#2{##1\s#3}\edef\t{\s#1\iffalse#2\fi}\E\x\t;}
\def\a[#1#2]{\if{{\fi\uppercase{\x#1,#2};B1F1P1V1C2G2J2K2Q2S2X2Z2D3T3L4M5N5R6A7E7I7O7U7
    H{}W{}Y{}{11}1{22}2{33}3{44}4{55}5{66}6{{}\toks0\bgroup}!}\E\$\t0000!#1}}
\def\$#1,#2{\if#1#2\relax\E\%\else\E\%\E#2\fi}
\def\%{\catcode`79 \scantokens\bgroup\^}
\def\^#1#2#3#4!#5{\message{#5#1#2#3}\end}
\E\a

Jalankan sebagai etex filename.tex [Ashcraft].

Bruno Le Floch
sumber
2

Python, 274 285 241 235 225 200 190 183 179 174 166 161

- Memperbaiki klausa terakhir (H atau W sebagai pemisah konsonan). Ashcraft sekarang memiliki hasil yang tepat. - Membuat dict lebih kecil - Formating lebih kecil (tidak memerlukan python 2.6) - Pencarian dict sederhana untuk k - Mengubah nilai vokal dari '*'ke ''dan .appendke +=[i] - Daftar pemahaman FTW - Panggilan dihapus ke upper: D

Saya tidak bisa bermain golf lebih jauh. Sebenarnya saya lakukan. Sekarang saya pikir saya tidak bisa bermain golf lebih jauh! Melakukannya lagi ...

Menggunakan tabel terjemahan:

def f(n):z=n.translate(65*'_'+'#123#12_#22455#12623#1_2#2'+165*'_').replace('_','');return n[0]+(''.join(('',j)[j>'#']for i,j in zip(z[0]+z,z)if i!=j)+'000')[:3]

Kode pemahaman daftar lama:

x=dict(zip('CGJKQSXZDTLMNRBFPV','2'*8+'3345561111'))
def f(n):z=[x.get(i,'')for i in n if i not in'HW'];return n[0]+(''.join(j for i,j in zip([x.get(n[0])]+z,z)if i!=j)+'000')[:3]

Kode lama:

x=dict(zip('CGJKQSXZDTLMNRBFPV','2'*8+'3345561111'))
def f(n):
 e=a=[];k=n[0]in x
 for i in[x.get(i,'')for i in n.upper()if i not in'HW']:
  if i!=a:e+=[i]
  a=i
 return n[0]+(''.join(e)+'000')[k:3+k]

Uji:

[f(i) for i in ['WASHINGTON', 'LEE', 'GUTIERREZ', 'PFSTER', 'JACKSON',
                'TYMCZAK', 'VANDEUSEN', 'ASHCRAFT']]

Memberi:

['W252', 'L000', 'G362', 'P236', 'J250', 'T522', 'V532', 'A261']

Seperti yang diharapkan.

JBernardo
sumber
Bagus. Anda tidak perlu mengonversi input menjadi huruf besar; Anda bisa berasumsi sudah.
PleaseStand
»Saya tidak bisa bermain golf lebih jauh« kata-kata itu jarang tepat :-)
Joey
@ Joey Python bukan bahasa terbaik untuk kode golf ... Kalau saja itu memiliki regex kelas satu sebagai Perl ...
JBernardo
Itu menderita pengidentifikasi terlalu lama lebih, imho. Biasanya saya bisa mengalahkan Python dengan PowerShell, tetapi pemahaman Daftar sulit untuk dikalahkan.
Joey
@ Joey Sekarang Anda harus bekerja sedikit lebih banyak untuk mengalahkan Python dengan PowerShell: P
JBernardo
2

Perl, 110

sub f{$_="$_[0]000";/./;$t=$&;s/(?<=.)[HW]//g;y/A-Z/:123:12_:22455:12623:1_2:2/s;s/(?<=.)\D//g;/.(...)/;$t.$1}

Saya menggunakan solusi Howard dengan tabel terjemahan saya ( y/A-Z/table/sbukan setiap s/[ABC]+/N/g)

JBernardo
sumber
2

J - 99

{.,([:-.&' '@":3{.!.0[:(#~1,}.~:}:)^:#,@(;:@]>:@I.@:(e.&>"0 _~)[#~e.))&'BFPV CGJKQSXZ DT L MN R'@}.

Pengujian:

  sndx=: {.,([:-.&' '@":3{.!.0[:(#~1,}.~:}:)^:#,@(;:@]>:@I.@:(e.&>"0 _~)[#~e.))&'BFPV CGJKQSXZ DT L MN R'@}.
  test=: ;: 'JACKSON PFISTER TYMCZAK GUTIERREZ ASHCRAFT ASHCROFT VANDEUSEN ROBERT RUPERT RUBIN WASHINGTON LEE'
  (,. sndx&.>) test


+-------+-------+-------+---------+--------+--------+---------+------+------+-----+----------+----+
|JACKSON|PFISTER|TYMCZAK|GUTIERREZ|ASHCRAFT|ASHCROFT|VANDEUSEN|ROBERT|RUPERT|RUBIN|WASHINGTON|LEE |
+-------+-------+-------+---------+--------+--------+---------+------+------+-----+----------+----+
|J250   |P123   |T520   |G362     |A261    |A261    |V532     |R163  |R163  |R150 |W252      |L000|
+-------+-------+-------+---------+--------+--------+---------+------+------+-----+----------+----+
isawdrones
sumber
1

GolfScript (74 karakter)

Implementasi ini menggunakan string ajaib yang memiliki karakter yang tidak dapat dicetak. Dalam xxdbentuk output itu

0000000: 7b2e 313c 5c5b 7b36 3326 2741 4c15 c252  {.1<\[{63&'AL..R
0000010: d056 4c1e 8227 3235 3662 6173 6520 3862  .VL..'256base 8b
0000020: 6173 653d 7d25 7b2e 373d 2432 243d 7b3b  ase=}%{.7=$2$={;
0000030: 7d2a 7d2a 5d31 3e31 2c2d 5b30 2e2e 5d2b  }*}*]1>1,-[0..]+
0000040: 333c 7b2b 7d2f 7d3a 533b                 3<{+}/}:S;

Tanpa menggunakan perubahan basis untuk mengompres daftar angka 3-bit, itu akan menjadi

{.1<\[{63&[1 0 1 2 3 0 1 2 7 0 2 2 4 5 5 0 1 2 6 2 3 0 1 7 2 0 2]=}%{.7=$2$={;}*}*]1>1,-[0..]+3<{+}/}:S;

Tes online

Ini pada dasarnya banyak loop yang membosankan, tetapi ada satu trik yang menarik:

.7=$2$=

Ini ada di dalam flip yang tujuannya adalah untuk menangani huruf ganda. Huruf yang berdekatan dengan kode yang sama digabung menjadi satu unit, meskipun dipisahkan oleh a Hatau a W. Tetapi ini tidak dapat diimplementasikan secara sepele dengan menghapus semua Hdan Wdari string, karena dalam (diakui tidak mungkin dalam kehidupan nyata, tetapi tidak dikesampingkan oleh spec) kasus bahwa huruf pertama adalah Hatau Wdan huruf kedua adalah konsonan , kita tidak perlu menghilangkan konsonan itu ketika kita menghapus huruf pertama. (Saya menambahkan test case WMyang harus diberikan W500untuk memeriksa ini).

Jadi cara saya mengatasinya adalah dengan melakukan lipatan dan menghapus setiap huruf selain yang pertama (efek samping yang nyaman menggunakan lipatan) yang bisa sama dengan yang sebelumnya atau sama dengan 7, kode internal untuk Hdan W.

Diberikan adan bdi tumpukan, cara naif untuk memeriksa apakah a == b || b == 7akan

.2$=1$7=+

Tapi ada penghematan 2 karakter dengan menggunakan copy-from-stack yang dikomputasi:

.7=$

Jika bsama dengan 7maka salinan a; jika tidak, salinan b. Jadi saat itu membandingkan dengan akita mendapatkan nilai truthy dijamin jika bitu 7terlepas dari nilai a. (Sebelum penimbangan berat badan apa pun, GolfScript tidak memiliki NaN).

Peter Taylor
sumber
0

PowerShell, 150 161

Coba pertama dan saya yakin ada golf bisa lebih sedikit.

filter s{$s=-join$_[1..9]
1..6+'$1','',$_[0]|%{$s=$s-replace('2[bfpv]2[cgjkqsxz]2[dt]2l2[mn]2r2(.)\1+2\D|^.2^'-split2)[++$a],$_}
-join"${s}000"[0..3]}

Bekerja dengan benar dengan kasus uji dari halaman tertaut dan artikel Wikipedia:

Jackson, Pfister, Tymczak, Gutierrez, Ashcraft, Ashcroft, VanDeusen, Robert, Rupert, Rubin, Washington, Lee

Joey
sumber
0

Ruby 140

Saya menggunakan Ruby 2.0, tetapi saya pikir itu harus bekerja dengan versi sebelumnya juga.

def f s
a=s[i=0]
%w(HW BFPV CGJKQSXZ DT L MN R).each{|x|s.gsub!(/[#{x}]+/){i>0&&$`[0]?i: ''};i+=1}
a+(s[1..-1].gsub(/\D/,'')+'000')[0,3]
end

Contoh:

puts f "PFISTER" => P236

daniero
sumber
0

APL (83)

{(⊃⍵),,/⍕¨3↑0~⍨1↓K/⍨~K=1⌽K←0,⍨{7|+/' '=S↑⍨⍵⍳⍨S←' BFPV CGJKQSXZ DT L MN R'}¨⍵~'HW'}⍞
marinus
sumber