Tugas ini adalah untuk menghasilkan jalur terpendek ke file, setelah ekspansi global.
Apa itu shell globbing? Di sebagian besar shell, Anda dapat menggunakan *
karakter di jalur untuk mewakili karakter apa pun di posisi. Misalnya, Jika direktori foo
berisi file bar
baz
dan asdf
, maka foo/b*
akan diperluas ke foo/bar foo/baz
.
Sekarang, katakanlah direktori saat ini berisi file yang dipanggil ihavealongname
dan tidak ada yang lain. Jika saya ingin mereferensikan file ini, saya mungkin mengetik *
, yang hanya akan mewakili satu file, daripada mengetikkan nama lengkap.
Jika direktori juga berisi file bernama ialsohavealongname
, saya tidak bisa melakukannya *
, karena akan cocok dengan kedua file. Saya harus melakukan, setidaknya ih*
,.
The *
Pola juga bekerja untuk pencocokan direktori di atas file yang saya cari. Jika hanya ada dua direktori foo
dan bar
, namun foo
hanya berisi file baz
dan bar
berisi file asdf
, saya bisa cocok foo/baz
dengan */baz
. Atau, bahkan lebih ringkas */b*
,. Jika bar
kosong, */*
pasti berhasil.
Tugas Anda: Diberikan larik string lintasan yang mewakili "direktori saat ini" dan lintasan target tunggal, output string sesingkat mungkin yang akan diperluas ke hanya lintasan target itu setelah memperluas * s.
Path target dapat diambil sebagai string miliknya, sebagai indeks ke dalam array path, sebagai item pertama pada array path yang dilewati, atau beberapa cara mudah lainnya yang bukan hard-coding. Tanyakan dalam komentar jika tidak yakin.
Jalur target dijamin akan ada di "direktori saat ini".
Anda dapat mengasumsikan bahwa semua jalur hanya berisi ASCII alfanumerik (dan /
s). Anda dapat mengambil jalur input yang di-root (mulai dengan /
) atau relatif (jangan mulai dengan /
).
Jika ada beberapa kemungkinan yang sama pendeknya, kembalikan salah satu atau semuanya.
Ini adalah kode-golf , byte terkecil menang!
Uji kasus , terima kasih kepada Kevin Cruijssen .
sumber
*
,?
,[
dll? Mungkin akan lebih mudah jika Anda hanya menyatakan bahwa nama file dan direktori adalah alfanumerik*
dan menjalankan perlglob
untuk mendapatkan semua nama file yang bisa relevan (misalnyafoo/bar/baz
menjadi*/*/*
). Setelah itu menjadi tantangan pemrosesan string. Dan tantangan itu sudah cukup sulit. Saya pikir tantangan ini akan lebih bersih karena "diberi daftar/
jalur relatif alfanumerik (dan ), temukan bola terpendek yang hanya cocok dengan jalur target yang ada inia*f
untuk memilihazzf
dariazzf
,azzg
,bzzf
. Perpanjang sesuka hati kea*b*c
dll.Jawaban:
Perl 5 ,
136107102 byteTermasuk
+2
untukn0
Berikan daftar file di STDIN. Yang pertama diasumsikan sebagai file target
Hanya kode tanpa membuat baris baru literal:
Gangguan sengaja setelah mencetak solusi.
Masih terasa terlalu lama (penggunaan
$a
dan1/0
sangat canggung), tapi ini awal dan harus cukup efisien.Cobalah online!
Bagaimana itu bekerja
Program ini membangun kandidat gumpalan dengan menumbuhkan mereka dari belakang ke depan dimulai dengan string kosong. Hal ini dilakukan dengan cara pertama luasnya, gumpalan jadi pertama-panjang 0 yang mencoba (hanya ``), maka panjang 1 (seperti
t
,i
,*
), selanjutnya panjang 2 (sepertifb
,i*
,*g
,**
), panjang berikutnya 3 dan seterusnya sampai glob ditemukan yang hanya cocok dengan jalur pertama. Ini kemudian akan menjadi bola terpendek yang memecahkan masalah (orang lain dengan panjang yang sama mungkin ada).Gumpalan panjang
n+1
dihasilkan dari gumpalan panjangn
dengan mendahului setiap karakter dari daftar jalur dan juga*
di depan setiap gumpalan panjangn
. Jadi misalnya panjang 3 gumpal*i*
akan memberikan kontribusi panjang 4 gumpalanf*i*
,o*i*
,o*i*
,/*i*
,b*i*
...s*i*
,t*i*
dan akhirnya**i*
. Perhatikan bahwa setiap karakter dari daftar jalur input akan didahulukan bahkan jika itu muncul beberapa kali atau tidak masuk akal karena mengarah ke sesuatu yang tidak pernah bisa cocok.Melakukan ini dengan naif akan menyebabkan ledakan kombinatorial. Itulah mengapa setiap kandidat bola akan dievaluasi untuk seberapa berguna itu dengan menentukan pada titik mana di jalan itu bisa cocok jika bola digunakan pada akhir bola lengkap. Saya melakukan ini dengan memasukkan a
;
di setiap tempat di mana pertandingan mungkin terjadi. Sebagai contoh untuk globt*
saya akan mendapatkan string:Ini mewakili "kekuatan pembeda" dari bola. Setiap bola yang memiliki kekuatan pembeda yang sama persis sama baiknya. Jika Anda menggantinya satu sama lain di akhir gumpalan lengkap mereka semua akan sama persis dengan jalur yang sama. Jadi Anda bisa menggunakan yang terpendek.
Jadi ketika mempertimbangkan panjang
n
gumpalan saya pertama kali melihat kekuatannya yang membedakan. Jika sudah terlihat sebelumnya ada gumpalan lain yang panjangn
atau lebih pendek yang sudah dipertimbangkan dan diperluas, sehingga gumpalan ini tidak ada gunanya dan dipangkas. Sebagai contoh, ini akan menyingkirkan kandidat seperti**i*
karena kekuatan pembeda yang sama sudah terlihat*i*
. Ini juga memangkas calon yang tidak mungkin sepertif*i*
karena string pembeda tidak akan memiliki;
dan hanya menjadi daftar jalur asli. Hanya gumpalan mustahil pertama yang akan diterima, semua gumpalan lainnya akan dianggap memiliki kekuatan pembeda yang sama dan akan dipangkas. Dan bahkan yang pertama tidak akan benar-benar diperluas karena semua ekspansi masih mustahil dan akan dipangkas ketika mereka dipertimbangkan. Secara bersamaanin*
akan dipangkas olehi*
dll.Hal di atas mengarah pada pemangkasan yang sangat agresif dan karena itu program ini dapat menangani kasus yang rumit dalam waktu yang sangat singkat. Namun, inefisiensi utama adalah bahwa prefixes the glob kandidat dengan semua karakter yang mungkin, tidak hanya yang sebelum bagian
;
target jalur dari string yang membedakan. Semua karakter tambahan yang tidak di depan;
tidak ada masalah karena mereka mengarah ke gumpalan mustahil yang akan dipangkas ketika dipertimbangkan, tetapi itu masih meninggalkan karakter sebelum;
di jalur lain. Jadi pada akhirnya program ini juga membangun gumpalan yang akan dapat cocok dengan semua kombinasi dari jalur yang diberikan. Ia tidak tahu bahwa ia harus berkonsentrasi pada jalan pertama.Sekarang pertimbangkan solusi untuk masalah tersebut. Dalam contoh yang diberikan bisa jadi
*/*er/t
. Ini memberikan string pembeda berikut:Saya mengenali solusi dengan memiliki
;
di posisi pertama (sehingga cocok dengan jalur pertama) dan tidak memiliki;
di awal jalur lain (sehingga yang lain tidak cocok)Dengan algoritme yang dijelaskan, saya sekarang mendapatkan program yang sebenarnya:
Caleg Glob akan berada dalam array
@a
yang saya gunakan menggunakan variabel$a
yang mengandung glob yang sedang dipertimbangkan. Alih-alih*
di glob, saya akan menggunakan\w*
jadi$a
sebenarnya regex bukan glob. Saya akan menyalahgunakan keanehan perl untuk loop yang Anda dapat menambahkan elemen ke array yang dilingkarkan saat loop sedang berjalan dan elemen-elemen baru ini akan diambil dalam loop. Karena ketika menghasilkann+1
gumpalan panjang semuan
gumpalan panjang sudah di array@a
ini adalah luasnya pertama.Karena
-n0
opsi (loop implisit di seluruh input) daftar jalur adalah$_
sebagai satu string besar dengan setiap jalur diakhiri dengan baris baruDi dalam
{ }
kita memiliki:Ups, saya baru saja menghancurkan
$_
dan saya akan membutuhkannya untuk loop berikutnya. Jadi bungkus kode kerja yang sebenarnya di dalamIni cocok dengan string kosong di awal
$_
dan memungkinkan Anda untuk menjalankan kode untuk menentukan apa yang akan diganti dengannya. Jika saya memastikan bahwa kode itu mengevaluasi ke string kosong$_
akan pada akhirnya tetap tidak berubah bahkan jika saya berubah$_
selamacode
.Kembali ke setelah saya diganti
$_
oleh string pembeda:Ini seperti:
//
di perl adalah'defined or
. Ini seperti hubungan arus pendek dior
mana argumen kedua hanya dievaluasi jika yang pertama adalahundef
. Dan itu dapat dikombinasikan dengan tugas seperti+=
dalam beberapa bahasa lainnya. Jadi jika mereka memasukkan$_
hash%seen
adalahundef
(yang adalah apa yang Anda dapatkan ketika mengakses elemen yang tidak ada) hanya kemudian jalankan ekspresi dan tetapkan sebagai nilai untuk kunci$_
. Jadi jika saya pastikanexpression
tidak mengembalikanundef
itu pada dasarnya berarti "mengevaluasi ekspresi jika dan hanya jika ini adalah pertama kalinya kita melihat string pembeda tertentu". Dan karena$_
dijamin mengandung\n
itu sebenarnya aman untuk menyalahgunakan perl global untuk menyimpan string yang membedakan, jadi$$_
alih-alih$seen{$_}
Untuk
expression
saya gunakan:Pada dasarnya "Untuk setiap karakter (kecuali baris baru) dalam string yang membedakan dan juga
*
menambahkannya ke gumpalan saat ini dan mendorongnya pada susunan kandidat glob". Kutipan yang saya gunakan\w*
untuk*
mendapatkan regex yang valid (saya bisa menggunakan''
alih-alih""
menyingkirkan satu backslash tapi kemudian saya tidak bisa menjalankan kode dari baris perintah). Perhatikan bahwa ini juga mengambil;
dan menambahkannya ke gumpalan kandidat tetapi ketika kemudian menguji mereka ke dipulihkan$_
yang tidak memiliki;
itu lagi akan menjadi gumpalan mustahil dan dipangkas.Perhatikan bahwa
/^;/>/\n;/
memiliki nilai yang setara dengan string kosong jika solusi belum ditemukan, jadi ini akan berfungsi sebagai string pengganti kosong dan$_
akan dipulihkansumber
-E
Mengaktifkan tingkat bahasa terbaru. Anda membutuhkan setidaknya perl5.10.0
agar dapat digunakansay
. Jadi letakkanuse 5.10.0;
di bagian header dan itu akan berhasil. Pilihan untuk mengatur jumlah level bahasa sebagai gratis, bahkan jika Anda juga tidak bisa menggunakannya-E
. Sebenarnya semua opsi dihitung sebagai gratis saat ini (jadi saya bahkan tidak perlu menghitungn0
) tapi saya menganggap itu terlalu toleran untuk perl1/
solusi Anda valid! Saya perlu mengingatnya juga ...Java 10,
854824796738728703688655652647624 byteBenar-benar berantakan .. Ini tentu bukan tantangan yang mudah di Jawa.
Pasti bisa bermain golf beberapa ratus byte, tapi aku senang akhirnya bisa bekerja sekarang.Saya kan sudah bilang. :)-5 byte terima kasih kepada @ceilingcat .
-23 byte beralih dari Java 8 ke Java 10
Input sebagai String-array path-file (dengan direktori sebagai item yang terpisah, dan semua item yang mengandung leading
/
), dan String dengan input path-file ke grop.Penjelasan:
Cobalah online. (Kasus uji dengan
ialsohavealongname
/ihavealongnameaswell
sedikit berkurang panjangnya dans.add(x.replaceAll("~+","\\*"));
telah diganti dengan{s.remove(x);s.add(x.replaceAll("~+","\\*"));}
bekerja dalam 5-10 detik pada TIO, alih-alih waktu habis setelah 60+ detik.)Penjelasan umum tambahan:
Contoh: Mari kita ambil
/foo, /foo/bar, /foo/barber, /foo/bar/test, /foo/barber/test, /foo/barber/testing, /foo/barber/coding, /foo/test
jalur file yang diberikan, danfoo/bar/test
sebagai input jalur file ke grop.1) Saya mulai dengan memisahkan input path file
/
, dan menghasilkan semua file-groppings dari kata-kata yang dipisahkan ini:2) Saya kemudian menghasilkan semua permutasi dengan kata-kata ini dalam urutan yang sama (menerapkan kembali
/
di antara dan di depan):3) Kemudian saya mengulang item dalam daftar di atas dan memvalidasi jika hanya cocok dengan satu path file dalam array input dari path file. (Saya melakukan ini dengan memeriksa dua hal: adalah jumlah garis miring yang sama, dan apakah itu cocok dengan regex di mana setiap
*
diganti dengan.*
.)Jika ya: pertahankan (pertama) terpendek, yang kita kembalikan pada akhirnya.
sumber
>>>
? Saya tahu>>
adalah bitwise shift kanan.>>>
bertindak sama dengan>>
. Tetapi untuk bilangan bulat negatif itu mengubah bit paritas menjadi 0 (Anda dapat melihat beberapa contoh di sini di bagian " >> vs >>> " ).-1>>>1
hanya varian yang lebih pendek dariInteger.MAX_VALUE
(dan1<<31
akan menjadiInteger.MIN_VALUE
).