Pertimbangkan array berikut:
/www/htdocs/1/sites/lib/abcdedd
/www/htdocs/1/sites/conf/xyz
/www/htdocs/1/sites/conf/abc/def
/www/htdocs/1/sites/htdocs/xyz
/www/htdocs/1/sites/lib2/abcdedd
apa cara terpendek dan paling elegan untuk mendeteksi jalur basis umum - dalam hal ini
/www/htdocs/1/sites/
dan menghapusnya dari semua elemen dalam array?
lib/abcdedd
conf/xyz
conf/abc/def
htdocs/xyz
lib2/abcdedd
Jawaban:
Tulis fungsi
longest_common_prefix
yang menggunakan dua string sebagai masukan. Kemudian terapkan ke string dalam urutan apa pun untuk menguranginya menjadi awalan umum. Karena asosiatif dan komutatif, urutan tidak menjadi masalah untuk hasilnya.Ini sama dengan operasi biner lainnya seperti misalnya penjumlahan atau pembagi persekutuan terbesar.
sumber
Muat mereka ke dalam struktur data trie. Mulai dari simpul induk, lihat mana yang memiliki anak terhitung lebih dari satu. Setelah Anda menemukan simpul ajaib itu, cukup bongkar struktur simpul induk dan miliki simpul saat ini sebagai root.
sumber
sumber
/usr/lib
dan/usr/lib2
itu memberi/usr/lib
sebagai jalur umum terpanjang, daripada/usr/
). Saya (semoga) memperbaiki keduanya.Nah, mengingat bahwa Anda dapat menggunakan
XOR
dalam situasi ini untuk menemukan bagian-bagian umum dari string. Setiap kali Anda x atau dua byte yang sama, Anda mendapatkan nullbyte sebagai output. Jadi kita bisa menggunakannya untuk keuntungan kita:Setelah loop tunggal itu,
$length
variabel akan sama dengan basepart umum terpanjang di antara array string. Kemudian, kita dapat mengekstrak bagian umum dari elemen pertama:Dan begitulah. Sebagai fungsi:
Perhatikan bahwa itu menggunakan lebih dari satu iterasi, tetapi iterasi itu dilakukan di perpustakaan, jadi dalam bahasa yang ditafsirkan ini akan memiliki keuntungan efisiensi yang besar ...
Sekarang, jika Anda hanya menginginkan jalur lengkap, kita perlu memotong ke
/
karakter terakhir . Begitu:Sekarang, itu mungkin terlalu memotong dua string seperti
/foo/bar
dan/foo/bar/baz
akan dipotong/foo
. Tetapi singkatnya menambahkan putaran iterasi lain untuk menentukan apakah karakter berikutnya adalah salah satu/
atau akhir string, saya tidak dapat melihat jalan keluarnya ...sumber
Pendekatan yang naif akan meledakkan jalur di
/
dan secara berturut-turut membandingkan setiap elemen dalam array. Jadi misalnya elemen pertama akan kosong di semua larik, jadi itu akan dihapus, elemen berikutnya akanwww
, itu sama di semua larik, jadi itu dihapus, dll.Sesuatu seperti (
belum dicoba)Setelah itu Anda hanya perlu meledakkan elemen
$exploded_paths
lagi:Yang memberi saya:
Ini mungkin tidak berskala dengan baik;)
sumber
Oke, saya tidak yakin ini anti peluru, tapi menurut saya ini berhasil:
Ini akan mengambil nilai pertama dalam array sebagai string referensi. Kemudian itu akan mengulangi string referensi dan membandingkan setiap karakter dengan karakter dari string kedua pada posisi yang sama. Jika sebuah karakter tidak cocok, string referensi akan disingkat menjadi posisi karakter tersebut dan string berikutnya akan dibandingkan. Fungsi ini akan mengembalikan string pencocokan terpendek.
Performa tergantung pada string yang diberikan. Semakin awal string referensi semakin pendek, semakin cepat kode akan selesai. Saya benar-benar tidak tahu bagaimana memasukkannya ke dalam formula.
Saya menemukan bahwa pendekatan Artefacto untuk mengurutkan string meningkatkan kinerja. Menambahkan
sebelum
array_reduce
secara signifikan meningkatkan kinerja.Perhatikan juga bahwa ini akan mengembalikan substring awal yang paling lama cocok , yang lebih serbaguna tetapi tidak akan memberi Anda jalur yang sama . Kamu harus lari
pada hasil. Dan kemudian Anda dapat menggunakan hasilnya untuk menghapus nilainya
yang seharusnya memberi:
Umpan balik diterima.
sumber
Anda dapat menghapus awalan dengan cara tercepat, membaca setiap karakter hanya sekali:
sumber
Keuntungannya adalah tidak memiliki kompleksitas waktu linier; Namun, untuk kebanyakan kasus, jenis ini pasti tidak akan memakan waktu lebih lama.
Pada dasarnya, bagian pintar (setidaknya saya tidak dapat menemukan kesalahan dengannya) di sini adalah bahwa setelah menyortir Anda hanya perlu membandingkan jalur pertama dengan yang terakhir.
sumber
EDIT Varian dari metode asli saya menggunakan array_walk untuk membangun kembali array
EDIT
Jawaban yang paling efisien dan elegan kemungkinan besar melibatkan pengambilan fungsi dan metode dari setiap jawaban yang diberikan
sumber
Saya akan
explode
nilai berdasarkan / dan kemudian digunakanarray_intersect_assoc
untuk mendeteksi elemen umum dan memastikan mereka memiliki indeks yang sesuai dalam array. Array yang dihasilkan dapat digabungkan kembali untuk menghasilkan jalur yang sama.Ini belum teruji, tetapi, idenya adalah bahwa
$commonPath
larik hanya pernah berisi elemen jalur yang telah dimuat dalam semua larik lintasan yang telah dibandingkan dengannya. Ketika loop selesai, kita hanya menggabungkannya kembali dengan / untuk mendapatkan true$commonPath
Perbarui Seperti yang ditunjukkan oleh Felix Kling,
array_intersect
tidak akan mempertimbangkan jalur yang memiliki elemen umum tetapi dalam urutan yang berbeda ... Untuk mengatasi ini, saya menggunakanarray_intersect_assoc
bukannyaarray_intersect
Perbarui kode yang ditambahkan untuk menghapus jalur umum (atau tetris itu!) Dari array juga.
sumber
/a/b/c/d
dan/d/c/b/a
. Elemen yang sama, jalur yang berbeda.Masalah tersebut dapat disederhanakan jika dilihat dari sudut perbandingan senar. Ini mungkin lebih cepat daripada pemisahan array:
sumber
Mungkin porting algoritma yang digunakan Python
os.path.commonprefix(m)
akan berhasil?Itu adalah, uh ... sesuatu seperti itu
Setelah itu Anda hanya dapat membuat substr setiap elemen dari daftar asli dengan panjang awalan umum sebagai offset awal.
sumber
Aku akan melempar topiku ke dalam ring…
Pemakaian:
sumber
Nah, sudah ada beberapa solusi di sini tapi, hanya karena menyenangkan:
Keluaran:
sumber
Ini berfungsi dengan baik ... mirip dengan mark baker tetapi menggunakan str_replace
sumber
Mungkin terlalu naif dan noobish tapi berhasil. Saya telah menggunakan algoritma ini :
Keluaran:
:)
sumber
/www/htdocs/1/sites/conf/
sebagai kecocokan umum. Selain itu, algoritme mencari substring yang dimulai di mana saja dalam string, tetapi untuk pertanyaan ini Anda tahu bahwa Anda bisa mulai dari lokasi 0, yang membuatnya lebih sederhana.