Saya ingin menghitung karakter C's G's N's dan "-" dalam sebuah file, atau setiap huruf jika diperlukan, apakah ada perintah Unix cepat untuk melakukan ini?
command-line
unix
shell
characters
Kirstin
sumber
sumber
[System.IO.File]::ReadAllText("C:\yourfile.txt").ToCharArray() | Group-Object $_ | Sort Count -Descending
Get-Content "C:\eula.3082.txt" | % { $_.ToCharArray() } | Group-Object | Sort Count -Descending
Jawaban:
Jika Anda menginginkan kecepatan nyata:
Adalah pseudo-one-liner yang sangat cepat.
Sebuah tes sederhana menunjukkan bahwa pada Core i7 CPU 870 @ 2.93GHz saya menghitung lebih dari 600MB / s:
Tidak seperti solusi yang melibatkan penyortiran, yang ini berjalan dalam memori konstan (4K), yang sangat berguna, jika file Anda jauh lebih besar daripada ram Anda.
Dan, tentu saja dengan sedikit minyak siku, kita dapat mencukur 0,7 detik:
Jaring lebih dari 1,1GB / detik finishing di:
Sebagai perbandingan, saya menguji beberapa solusi lain pada halaman ini yang tampaknya memiliki semacam janji kecepatan.
The
sed
/awk
solusi membuat usaha gagah berani, namun meninggal setelah 30 detik. Dengan regex yang sederhana, saya berharap ini menjadi bug in sed (GNU sed versi 4.2.1):Metode perl juga tampak menjanjikan, tetapi saya menyerah setelah menjalankannya selama 7 menit
sumber
grep -o foo.text -e A -e T -e C -e G -e N -e -|sort|uniq -c
Akan melakukan trik sebagai liner satu. Namun diperlukan sedikit penjelasan.
grep -o foo.text -e A -e T -e C -e G -e N -e -
greps file foo.text untuk huruf a dan g dan karakter-
untuk setiap karakter yang ingin Anda cari. Ini juga mencetak satu karakter satu garis.sort
mengurutkannya secara berurutan. Ini mengatur panggung untuk alat selanjutnyauniq -c
menghitung duplikat kemunculan berurutan dari sembarang baris. Dalam hal ini, karena kami memiliki daftar karakter yang diurutkan, kami mendapatkan jumlah yang rapi kapan karakter yang kami ambil pada langkah pertamaJika foo.txt berisi string,
GATTACA-
inilah yang akan saya dapatkan dari serangkaian perintah inisumber
-o
.Coba yang ini, terinspirasi oleh jawaban @ Journeyman.
Kuncinya adalah mengetahui tentang opsi -o untuk grep . Ini membagi kecocokan, sehingga setiap baris output sesuai dengan satu contoh pola, daripada seluruh baris untuk setiap baris yang cocok. Dengan pengetahuan ini, yang kita butuhkan hanyalah pola untuk digunakan, dan cara menghitung garis. Dengan menggunakan regex, kita dapat membuat pola disjungtif yang akan cocok dengan karakter yang Anda sebutkan:
Ini berarti "cocok dengan A atau T atau C atau G atau N atau -". Manual ini menjelaskan berbagai sintaks ekspresi reguler yang dapat Anda gunakan .
Sekarang kita memiliki output yang terlihat seperti ini:
Langkah terakhir kami adalah menggabungkan dan menghitung semua baris yang sama, yang dapat diselesaikan dengan a
sort | uniq -c
, seperti dalam jawaban @ Journeyman. Sortir tersebut memberi kami output seperti ini:Yang, ketika disalurkan melalui
uniq -c
, akhirnya menyerupai apa yang kita inginkan:Tambahan: Jika Anda ingin total jumlah A, C, G, N, T, dan - karakter dalam file, Anda dapat menyalurkan output grep melalui
wc -l
bukansort | uniq -c
. Ada banyak hal berbeda yang dapat Anda hitung dengan hanya sedikit modifikasi pada pendekatan ini.sumber
Satu liner menghitung semua huruf menggunakan Python:
... menghasilkan keluaran ramah YAML seperti ini:
Sangat menarik untuk melihat bagaimana sebagian besar kali Python dapat dengan mudah mengalahkan bahkan bash dalam hal kejelasan kode.
sumber
Mirip dengan
awk
metode Guru :sumber
Setelah menggunakan UNIX selama beberapa tahun, Anda menjadi sangat mahir menghubungkan beberapa operasi kecil untuk menyelesaikan berbagai tugas penyaringan dan penghitungan. Setiap orang memiliki gaya mereka sendiri - beberapa suka
awk
dansed
, beberapa sukacut
dantr
. Inilah cara saya akan melakukannya:Untuk memproses nama file tertentu:
atau sebagai filter:
Ini berfungsi seperti ini:
od -a
memisahkan file menjadi karakter ASCII.cut -b 9-
menghilangkanod
menempatkan awalan .tr " " \\n
mengkonversi spasi antara karakter ke baris baru sehingga ada satu karakter per baris.egrep -v "^$"
menghilangkan semua baris kosong tambahan yang dibuat ini.sort
mengumpulkan contoh masing-masing karakter bersama-sama.uniq -c
menghitung jumlah pengulangan dari setiap baris.Saya memberinya makan "Halo, dunia!" diikuti oleh baris baru dan dapatkan ini:
sumber
Bagian
sed
yang didasarkan pada jawaban @ Guru , inilah pendekatan lain yang digunakanuniq
, mirip dengan solusi David Schwartz.sumber
[[:alpha:]]
daripada.
dised
hanya karakter pertandingan dan tidak baris.[[:alpha:]]
akan gagal jika Anda juga mencoba mencocokkan hal-hal seperti-
, yang disebutkan dalam pertanyaansed -e 's/[^ATCGN-]//g' -e 's/\([ATCGN-]\)/\1\n/g' foo | sort | uniq -c
. Namun, saya tidak tahu bagaimana cara menyingkirkan baris baru di sana: \Anda dapat menggabungkan
grep
danwc
melakukan ini:grep
mencari file yang diberikan untuk teks yang ditentukan, dan-o
opsi mengatakannya untuk hanya mencetak kecocokan yang sebenarnya (mis. karakter yang Anda cari), daripada default yang mencetak setiap baris di mana teks pencarian itu ditemukan pada.wc
mencetak byte, kata dan jumlah baris untuk setiap file, atau dalam hal ini, output darigrep
perintah. The-w
pilihan mengatakan itu untuk menghitung kata, dengan setiap kata menjadi terjadinya karakter pencarian Anda. Tentu saja,-l
opsi (yang menghitung garis) akan berfungsi juga, karenagrep
mencetak setiap kemunculan karakter pencarian Anda pada baris yang terpisah.Untuk melakukan ini untuk sejumlah karakter sekaligus, letakkan karakter dalam array dan loop di atasnya:
Contoh: untuk file yang berisi string
TGC-GTCCNATGCGNNTCACANN-
, hasilnya adalah:Untuk informasi lebih lanjut, lihat
man grep
danman wc
.Kelemahan dari pendekatan ini, seperti yang dicatat pengguna Journeyman Geek di bawah ini dalam komentar, adalah yang
grep
harus dijalankan satu kali untuk setiap karakter. Bergantung pada seberapa besar file Anda, ini dapat menyebabkan hit kinerja yang nyata. Di sisi lain, ketika dilakukan dengan cara ini sedikit lebih mudah untuk dengan cepat melihat karakter mana yang sedang dicari, dan untuk menambah / menghapusnya, karena mereka berada di baris terpisah dari sisa kode.sumber
uniq -c
juga sepertinya cara yang lebih baik untuk mendapatkan output yang diformat dengan baik. Saya bukan * nix guru, di atas adalah apa yang saya berhasil kumpulkan dari pengetahuan saya yang terbatas dan beberapa halaman manual :)Menggunakan garis urutan dari 22hgp10a.txt perbedaan waktu antara grep dan awk di sistem saya membuat menggunakan awk cara untuk pergi ...
[Sunting]: Setelah melihat solusi yang disusun Dave lupa awk juga, karena selesai dalam ~ 0,1 detik pada file ini untuk penghitungan peka huruf besar-kecil.
Versi case sensitif dari ghostdog selesai dalam ~ 14 detik.
Sed dijelaskan dalam jawaban yang diterima untuk pertanyaan ini .
Benchmarking adalah seperti pada jawaban yang diterima untuk pertanyaan ini .
Jawaban yang diterima oleh ghostdog74 adalah untuk pertanyaan ini .
sumber
s/cache[letters[x]]/cache[letters[x]]+cache[toupper(letters[x])]
menambang agar case-nya tidak sensitif tanpa mempengaruhi kecepatannya.Saya pikir setiap implementasi yang layak menghindari semacam itu. Tetapi karena itu juga ide yang buruk untuk membaca semuanya 4 kali, saya pikir seseorang dapat entah bagaimana menghasilkan aliran yang melewati 4 filter, satu untuk setiap karakter, yang disaring dan di mana panjang aliran juga entah bagaimana dihitung.
Jumlah kumulatif kemudian dalam tmp [0-6] .txt .. jadi pekerjaan masih berlangsung
Hanya ada 13 pipa dalam pendekatan ini, yang mengkonversi ke memori kurang dari 1 Mb.
Tentu saja solusi favorit saya adalah:
sumber
tr
.Saya tidak tahu tentang
uniq
atau tentanggrep -o
, tetapi karena komentar saya di @JourneymanGeek dan @ crazy2be memiliki dukungan seperti itu, mungkin saya harus mengubahnya menjadi anwser sendiri:Jika Anda tahu hanya ada karakter "baik" (yang ingin Anda hitung) di file Anda, Anda bisa menggunakannya
Jika hanya beberapa karakter harus dihitung dan yang lainnya tidak (mis. Pemisah)
Yang pertama menggunakan wildcard ekspresi reguler
.
, yang cocok dengan karakter tunggal apa pun. Yang kedua menggunakan 'set karakter yang diterima', tanpa urutan tertentu, kecuali yang-
harus datang terakhir (A-C
ditafsirkan sebagai 'karakter apa saja antaraA
danC
). Diperlukan harga dalam kasus itu agar shell Anda tidak mencoba memperluasnya untuk memeriksa file satu karakter jika ada (dan menghasilkan kesalahan "tidak cocok" jika tidak ada).Perhatikan bahwa "sort" juga memiliki
-u
flag nique sehingga hanya melaporkan sesuatu sekali, tetapi tidak ada flag pendamping untuk menghitung duplikat, jadiuniq
memang wajib.sumber
-
tidak harus menjadi yang terakhir jika Anda menghindarinya dengan backslash:'[A\-CTGN]'
harus bekerja dengan baik.Yang konyol:
tr
untuk menghapus (-d
) semua karakter kecuali (-c
) ATCGN-iconv
untuk mengkonversi ke ucs2 (UTF16 terbatas pada 2 byte) untuk menambahkan 0 byte setelah setiap byte,tr
untuk menerjemahkan karakter NUL itu ke NL. Sekarang setiap karakter ada di jalurnya sendirisort | uniq -c
untuk menghitung setiap baris uniqItu alternatif untuk
-o
opsi grep non-standar (GNU) .sumber
Format output bukan yang terbaik ...
Teori Operasi:
Kecepatan tampaknya 60MBps +
sumber
File sampel:
Perintah:
sumber
Menggabungkan beberapa lainnya
Tambahkan
| sort -nr
untuk melihat hasil dalam urutan frekuensi.sumber
Jawaban singkat:
Jika keadaan memungkinkan, bandingkan ukuran file set karakter rendah ke satu tanpa karakter untuk mendapatkan offset dan hitung saja byte.
Ah, tapi detail yang kusut:
Itu semua adalah karakter Ascii. Satu byte per. File tentu saja memiliki metadata ekstra yang ditambahkan untuk berbagai hal yang digunakan oleh OS dan aplikasi yang membuatnya. Dalam kebanyakan kasus saya akan mengharapkan ini untuk mengambil jumlah ruang yang sama terlepas dari metadata tapi saya akan mencoba untuk mempertahankan keadaan yang sama ketika Anda pertama kali menguji pendekatan dan kemudian memverifikasi bahwa Anda memiliki offset konstan sebelum tidak khawatir tentang hal itu. Gotcha lainnya adalah bahwa jeda baris biasanya melibatkan dua karakter spasi ascii white dan setiap tab atau spasi akan masing-masing. Jika Anda dapat yakin ini akan hadir dan tidak ada cara untuk tahu berapa banyak sebelumnya, saya akan berhenti membaca sekarang.
Ini mungkin tampak seperti banyak kendala, tetapi jika Anda dapat dengan mudah membuat mereka, ini menurut saya sebagai pendekatan yang paling mudah / berkinerja terbaik jika Anda memiliki banyak hal untuk dilihat (yang tampaknya mungkin jika itu adalah DNA). Memeriksa satu ton file untuk panjang dan mengurangi konstanta akan lebih cepat daripada menjalankan grep (atau serupa) pada setiap file.
Jika:
Dan Dua Hal Yang Mungkin Bukan Masalah Tetapi Saya Akan Mengujinya terlebih dahulu
Coba Cari Offset Dengan Melakukan Hal Berikut:
Bandingkan file kosong dengan satu dengan beberapa karakter yang mudah dihitung manusia untuk satu dengan beberapa karakter lebih banyak. Jika mengurangi file kosong dari kedua file lainnya memberi Anda jumlah byte yang cocok dengan jumlah karakter, Anda sudah selesai. Periksa panjang file dan kurangi jumlah kosong itu. Jika Anda ingin mencoba mencari file multi-line, sebagian besar editor melampirkan dua karakter satu-byte khusus untuk jeda baris karena satu cenderung diabaikan oleh Microsoft tetapi Anda harus setidaknya memahami untuk chars white-space dalam hal ini Anda mungkin juga melakukan semuanya dengan grep.
sumber
Cara Haskell :
kerjanya seperti ini:
kompilasi dan penggunaan:
mungkin tidak bagus untuk file besar.
sumber
Perl hack cepat:
-n
: Ulangi jalur input tetapi jangan cetak apa pun untuknya-l
: Strip atau tambahkan jeda baris secara otomatiswhile
: beralihlah ke semua kemunculan simbol yang Anda minta di baris saat iniEND
: Pada akhirnya, hasil cetak%a
: Hash tempat nilai disimpanKarakter yang tidak muncul sama sekali tidak akan dimasukkan dalam hasil.
sumber