किसी फ़ाइल में प्रत्येक वर्ण की संख्या गिनने का सबसे तेज़ तरीका क्या है?


121

मैं ए टी के सी के जी के एन और "-" अक्षर को फ़ाइल में गिनना चाहता हूं, या यदि आवश्यक हो तो हर पत्र, क्या ऐसा करने के लिए एक त्वरित यूनिक्स कमांड है?


56
डीएनए स्ट्रैंड्स में काउंटिंग बेस?
Indrek

12
मुझे यह सवाल बहुत पसंद है, एक ही समस्या को हल करने के लिए इस्तेमाल किए गए कई अलग-अलग दृष्टिकोण और उपकरण।
जर्नीमैन गीक

10
हेह, यह बॉर्डरलाइन कोड-गोल्फ है
अर्लज़

13
अगर somone विंडोज़ के पॉवरशेल संस्करण में दिलचस्पी रखता है:[System.IO.File]::ReadAllText("C:\yourfile.txt").ToCharArray() | Group-Object $_ | Sort Count -Descending
Guillaume86

4
ठीक है, मुझे लगता है कि मुझे शुद्ध PS तरीका मिला:Get-Content "C:\eula.3082.txt" | % { $_.ToCharArray() } | Group-Object | Sort Count -Descending
Guillaume86

जवाबों:


136

यदि आप कुछ वास्तविक गति चाहते हैं:

echo 'int cache[256],x,y;char buf[4096],letters[]="tacgn-"; int main(){while((x=read(0,buf,sizeof buf))>0)for(y=0;y<x;y++)cache[(unsigned char)buf[y]]++;for(x=0;x<sizeof letters-1;x++)printf("%c: %d\n",letters[x],cache[letters[x]]);}' | gcc -w -xc -; ./a.out < file; rm a.out;

एक अविश्वसनीय रूप से तेज़ छद्म-वन-लाइनर है।

एक साधारण परीक्षण से पता चलता है कि मेरे कोर i7 सीपीयू 870 @ 2.93GHz पर इसकी गिनती सिर्फ 600MB / s से अधिक है:

$ du -h bigdna 
1.1G    bigdna

time ./a.out < bigdna 
t: 178977308
a: 178958411
c: 178958823
g: 178947772
n: 178959673
-: 178939837

real    0m1.718s
user    0m1.539s
sys     0m0.171s

सॉर्टिंग से जुड़े समाधानों के विपरीत, यह एक निरंतर (4K) मेमोरी में चलता है, जो बहुत उपयोगी है, अगर आपकी फ़ाइल आपके रैम से बहुत बड़ी है।

और, निश्चित रूप से थोड़ा सा कोहनी तेल से, हम 0.7 सेकंड से दाढ़ी बना सकते हैं:

echo 'int cache[256],x,buf[4096],*bp,*ep;char letters[]="tacgn-"; int main(){while((ep=buf+(read(0,buf,sizeof buf)/sizeof(int)))>buf)for(bp=buf;bp<ep;bp++){cache[(*bp)&0xff]++;cache[(*bp>>8)&0xff]++;cache[(*bp>>16)&0xff]++;cache[(*bp>>24)&0xff]++;}for(x=0;x<sizeof letters-1;x++)printf("%c: %d\n",letters[x],cache[letters[x]]);}' | gcc -O2 -xc -; ./a.out < file; rm a.out;

केवल 1.1GB / s पर खत्म होने वाले जाल:

real    0m0.943s
user    0m0.798s
sys     0m0.134s

तुलना के लिए, मैंने इस पृष्ठ पर कुछ अन्य समाधानों का परीक्षण किया, जो कि किसी प्रकार की गति का वादा करते थे।

sed/ awkसमाधान एक बहादुर प्रयास किया, लेकिन 30 सेकंड के बाद निधन हो गया। इस तरह के एक सरल रेगेक्स के साथ, मुझे उम्मीद है कि यह सीड (जीएनयू सेड संस्करण 4.2.1) में एक बग होगा।

$ time sed 's/./&\n/g' bigdna | awk '!/^$/{a[$0]++}END{for (i in a)print i,a[i];}' 
sed: couldn't re-allocate memory

real    0m31.326s
user    0m21.696s
sys     0m2.111s

पर्ल विधि भी आशाजनक लग रही थी, लेकिन मैंने इसे 7 मिनट तक चलाने के बाद छोड़ दिया

time perl -e 'while (<>) {$c{$&}++ while /./g} print "$c{$_} $_\n" for keys %c' < bigdna 
^C

real    7m44.161s
user    4m53.941s
sys     2m35.593s

1
+1 डेटा के बहुत सारे होने पर, और न केवल मुट्ठी भर बाइट्स के लिए एक सॉल्यूशन सॉल्यूशन के लिए। फ़ाइलें डिस्क कैश में हैं, हालांकि, वे नहीं हैं?
डैनियल बेक

2
साफ-सुथरी बात यह है कि इसमें प्रसंस्करण में O (N) और O (1) की जटिलता है। आमतौर पर पाइप में ओ (एन लॉग एन) प्रसंस्करण (या यहां तक ​​कि ओ (एन ^ 2)) और ओ (एन) स्मृति में होता है।
मार्टिन उडिंग

73
आप हालांकि "कमांड लाइन" की परिभाषा को काफी बढ़ा रहे हैं।
गेरिट

11
प्रश्न की आवश्यकताओं के महाकाव्य झुकने - मुझे मंजूर; पी। superuser.com/a/486037/10165 <- कोई मानक भाग गया, और यह है सबसे तेजी से विकल्प।
जर्नीमैन गीक

2
+1 मैं सही स्थानों में सी के कुछ अच्छे उपयोग की सराहना करता हूं।
जेफ फेरलैंड

119

grep -o foo.text -e A -e T -e C -e G -e N -e -|sort|uniq -c

एक लाइनर के रूप में चाल चलेगा। हालांकि थोड़ा स्पष्टीकरण की आवश्यकता है।

grep -o foo.text -e A -e T -e C -e G -e N -e -एक और जी अक्षर के लिए फ़ाइल foo.text greps और -प्रत्येक वर्ण जिसे आप खोजना चाहते हैं, के लिए वर्ण। यह भी एक चरित्र एक लाइन प्रिंट करता है।

sortइसे क्रम में रखें। यह अगले टूल के लिए स्टेज सेट करता है

uniq -cकिसी भी लाइन की डुप्लिकेट लगातार घटनाओं को गिनता है। इस मामले में, चूंकि हमारे पास वर्णों की एक क्रमबद्ध सूची है, इसलिए हमें पहले चरण में वर्णों को गिनने पर एक स्पष्ट गणना मिलती है।

अगर foo.txt में स्ट्रिंग है, तो GATTACA-यह वह है जो मुझे इस सेट के कमांड से मिलेगा

[geek@atremis ~]$ grep -o foo.text -e A -e T -e C -e G -e N -e -|sort|uniq -c
      1 -
      3 A
      1 C
      1 G
      2 T

8
खूनी यूनिक्स जादू! : D
पिटो

27
अगर आपकी फ़ाइलों में केवल CTAG- वर्ण हैं, तो regexp स्वयं व्यर्थ हो जाता है, है ना? grep -o | सॉर्ट | uniq -c समान रूप से अच्छी तरह से काम करेगा, afaik।
सिल्वेनुलग

7
+1 मैं 25 वर्षों से grep का उपयोग कर रहा हूं और इसके बारे में नहीं जानता -o
लार्स

9
@JourneymanGeek: इसके साथ समस्या यह है कि यह बहुत अधिक डेटा उत्पन्न करता है जिसे बाद में छाँटने के लिए भेजा जाता है। यह सस्ता होगा एक कार्यक्रम प्रत्येक चरित्र पार्स करने के लिए। डे के उत्तर को O (N) के बजाय O (N) मेमोरी जटिलता उत्तर के लिए देखें।
मार्टिन उडिंग

2
@Pitto नेटिव विन्डोज़ ऑफ़ क्रोडुटिल्स व्यापक रूप से उपलब्ध हैं - बस Google या
सोमेसच से

46

@ यात्री के जवाब से प्रेरित होकर, यह कोशिश करें।

grep -o -E 'A|T|C|G|N|-' foo.txt | sort | uniq -c

कुंजी grep के लिए -o विकल्प के बारे में जान रही है । यह मैच को विभाजित करता है, जिससे कि प्रत्येक आउटपुट लाइन पैटर्न के एक एकल उदाहरण से मेल खाती है, बजाय किसी भी लाइन के जो पूरी रेखा से मेल खाती है। इस ज्ञान को देखते हुए, हम सभी को उपयोग करने के लिए एक पैटर्न है, और लाइनों को गिनने का एक तरीका है। रेगेक्स का उपयोग करते हुए, हम एक ऐसा व्यवहारिक पैटर्न बना सकते हैं जो आपके द्वारा उल्लिखित किसी भी वर्ण से मेल खाएगा:

A|T|C|G|N|-

इसका मतलब है "मैच ए या टी या सी या जी या एन या -"। मैनुअल विभिन्न नियमित अभिव्यक्ति सिंटैक्स का वर्णन करता है जिनका आप उपयोग कर सकते हैं

अब हमारे पास आउटपुट है जो कुछ इस तरह दिखता है:

$ grep -o -E 'A|T|C|G|N|-' foo.txt 
A
T
C
G
N
-
-
A
A
N
N
N

हमारा अंतिम चरण सभी समान रेखाओं को मिलाना और गिनना है, जो केवल sort | uniq -c@ जर्म्समैन के जवाब में, एक के साथ पूरा किया जा सकता है । सॉर्ट हमें इस तरह से आउटपुट देता है:

$ grep -o -E 'A|T|C|G|N|-' foo.txt | sort
-
-
A
A
A
C
G
N
N
N
N
T

जब, के माध्यम से पाइप किया जाता है uniq -c, तो अंत में जैसा हम चाहते हैं, जैसा दिखता है:

$ grep -o -E 'A|T|C|G|N|-' foo.txt | sort | uniq -c
      2 -
      3 A
      1 C
      1 G
      4 N
      1 T

परिशिष्ट: यदि आप किसी फ़ाइल में A, C, G, N, T, और वर्णों की कुल संख्या चाहते हैं, तो आप के wc -lबजाय grep आउटपुट को पाइप कर सकते हैं sort | uniq -c। इस दृष्टिकोण में बहुत सी अलग-अलग चीजें हैं जिन्हें आप केवल मामूली संशोधनों के साथ गिन सकते हैं।


मैं वास्तव में rabbitholes कि मूल और regex हैं में तलना करने की जरूरत है। यह इसके लिए मेरा की तुलना में कुछ अधिक सुरुचिपूर्ण है, पी
जर्नीमैन गीक

2
@JourneymanGeek: Learing regex अच्छी तरह से परेशानी के लायक है, क्योंकि यह बहुत सी चीजों के लिए उपयोगी है। बस यह समझें कि यह सीमाएँ हैं, और एक्सपेरीज़ को पार्सल करने के प्रयास की तरह, रीपेक्सस कैपबिलिटीज़ के दायरे से बाहर की चीज़ों का उपयोग करके शक्ति का दुरुपयोग न करें ।
15:

20
grep -o '[ATCGN-]' यहाँ थोड़ा अधिक पठनीय हो सकता है।
सिल्वेनुलग

14

पायथन का उपयोग करके सभी अक्षरों की गिनती करने वाला एक लाइनर:

$ python -c "import collections, pprint; pprint.pprint(dict(collections.Counter(open('FILENAME_HERE', 'r').read())))"

... इस तरह एक YAML अनुकूल उत्पादन का उत्पादन:

{'\n': 202,
 ' ': 2153,
 '!': 4,
 '"': 62,
 '#': 12,
 '%': 9,
 "'": 10,
 '(': 84,
 ')': 84,
 '*': 1,
 ',': 39,
 '-': 5,
 '.': 121,
 '/': 12,
 '0': 5,
 '1': 7,
 '2': 1,
 '3': 1,
 ':': 65,
 ';': 3,
 '<': 1,
 '=': 41,
 '>': 12,
 '@': 6,
 'A': 3,
 'B': 2,
 'C': 1,
 'D': 3,
 'E': 25}

यह देखना दिलचस्प है कि कोड की स्पष्टता के मामले में पायथन कितनी बार आसानी से बाजी मार सकता है।


11

गुरु की awkविधि के समान :

perl -e 'while (<>) {$c{$&}++ while /./g} print "$c{$_} $_\n" for keys %c'

10

कुछ वर्षों के लिए UNIX का उपयोग करने के बाद, आपको विभिन्न फ़िल्टरिंग और गणना कार्यों को पूरा करने के लिए कई छोटे ऑपरेशनों को एक साथ जोड़ने में बहुत कुशल मिलता है। हर कोई अपने style-- कुछ की तरह है awkऔर sedकुछ की तरह cutऔर tr। यहाँ मैं यह करूँगा तरीका है:

किसी विशेष फ़ाइलनाम को संसाधित करने के लिए:

 od -a FILENAME_HERE | cut -b 9- | tr " " \\n | egrep -v "^$" | sort | uniq -c

या एक फिल्टर के रूप में:

 od -a | cut -b 9- | tr " " \\n | egrep -v "^$" | sort | uniq -c

यह इस तरह काम करता है:

  1. od -a फ़ाइल को ASCII वर्णों में अलग करता है।
  2. cut -b 9-उपसर्ग odडालता समाप्त करता है ।
  3. tr " " \\n वर्णों के बीच रिक्त स्थान को नई रेखाओं में परिवर्तित करता है इसलिए प्रति पंक्ति एक वर्ण होता है।
  4. egrep -v "^$" इससे बनने वाली सभी अतिरिक्त खाली लाइनों से छुटकारा मिल जाता है।
  5. sort प्रत्येक वर्ण के उदाहरणों को एक साथ इकट्ठा करता है।
  6. uniq -c प्रत्येक पंक्ति के दोहराव की संख्या गिनता है।

मैंने इसे "हैलो, दुनिया!" एक नई लाइन के बाद और यह मिला:

  1 ,
  1 !
  1 d
  1 e
  1 H
  3 l
  1 nl
  2 o
  1 r
  1 sp
  1 w

9

यह sedभाग @ गुरु के उत्तर पर आधारित है , यहां uniqडेविड श्वार्ट्ज के समाधान के समान एक अन्य दृष्टिकोण का उपयोग किया गया है ।

$ cat foo
aix
linux
bsd
foo
$ sed 's/\(.\)/\1\n/g' foo | sort | uniq -c
4 
1 a
1 b
1 d
1 f
2 i
1 l
1 n
2 o
1 s
1 u
2 x

1
का प्रयोग करें [[:alpha:]]बजाय .में sedकेवल मैच अक्षर और नहीं नई-पंक्तियों के लिए।
क्लोडिअस

1
[[:alpha:]]अगर आप भी सामान की तरह मिलान करने की कोशिश कर रहे हैं तो विफल हो जाएगा -, जो कि प्रश्न में उल्लेख किया गया था
इजाकाटा

सही बात। यह दूसरी अभिव्यक्ति को जोड़ने के लिए हो सकता है कि पहले हर चीज को छानने के लिए एक दूसरे एक्सप्रेशन को जोड़ा जाए और फिर वांछित पात्रों पर स्पष्ट रूप से मिलान किया जाए sed -e 's/[^ATCGN-]//g' -e 's/\([ATCGN-]\)/\1\n/g' foo | sort | uniq -c:। हालाँकि, मैं नहीं जानता कि कैसे वहाँ से छुटकारा पाने के लिए नए सिरे से: \
क्लॉडियस

7

आप इसे जोड़ सकते हैं grepऔर कर सकते हैं wc:

grep -o 'character' file.txt | wc -w

grepनिर्दिष्ट पाठ के लिए दिए गए फ़ाइल (ओं) को खोजता है, और -oविकल्प यह बताता है कि केवल वास्तविक मैचों को प्रिंट करें (यानी आपके द्वारा खोजे जा रहे अक्षर), बजाय डिफ़ॉल्ट के जो प्रत्येक पंक्ति को प्रिंट करने के लिए है जिसमें खोज पाठ था। पर पाया गया।

wcप्रत्येक फ़ाइल के लिए बाइट, वर्ड और लाइन काउंट को प्रिंट करता है, या इस स्थिति में, grepकमांड का आउटपुट । -wविकल्प यह बताता है प्रत्येक शब्द अपनी खोज चरित्र का एक घटना होने के साथ शब्दों की गिनती करने,। बेशक, -lविकल्प (जो लाइनों को गिनता है) भी grepएक अलग लाइन पर आपके खोज चरित्र की प्रत्येक घटना को प्रिंट करता है , साथ ही साथ काम करेगा ।

एक बार में कई वर्णों के लिए ऐसा करने के लिए, वर्णों को एक सरणी में रखें और उस पर लूप करें:

chars=(A T C G N -)
for c in "${chars[@]}"; do echo -n $c ' ' && grep -o $c file.txt | wc -w; done

उदाहरण: स्ट्रिंग वाली फ़ाइल के लिए TGC-GTCCNATGCGNNTCACANN-, आउटपुट होगा:

A  3
T  4
C  6
G  4
N  5
-  2

अधिक जानकारी के लिए, देखें man grepऔर man wc


इस दृष्टिकोण के नकारात्मक पक्ष, जैसा कि उपयोगकर्ता जर्नीमैन गीक ने एक टिप्पणी में नीचे नोट किया है, जिसे grepप्रत्येक चरित्र के लिए एक बार चलाया जाना है। आपकी फाइलें कितनी बड़ी हैं, इस पर निर्भर करते हुए, यह ध्यान देने योग्य प्रदर्शन को प्रभावित कर सकता है। दूसरी ओर, जब इस तरह से किया जाता है तो यह देखना थोड़ा आसान हो जाता है कि कौन से अक्षर खोजे जा रहे हैं, और उन्हें जोड़ने / हटाने के लिए, क्योंकि वे बाकी कोड से अलग लाइन पर हैं।


3
वे इसे सही करने के लिए प्रति बार दोहराना चाहते हैं ... मुझे जोड़ना होगा। मैं वहाँ एक और अधिक सुरुचिपूर्ण समाधान है, लेकिन इसे और अधिक poking की जरूरत है कसम खाता हूँ सकता है, पी
जर्नीमैन गीक

@JourneymanGeek अच्छा बिंदु। एक दृष्टिकोण जो मन में झरता है वह पात्रों को एक सरणी में रख रहा है और इसके माध्यम से लूप कर रहा है। मैंने अपनी पोस्ट अपडेट कर दी है।
Indrek

बहुत जटिल IMO। बस grep -ea -et इत्यादि का उपयोग करें। यदि आप इसे एक सरणी और पाश में रखते हैं, तो क्या आपको वर्ण के अनुसार एक बार grep चक्र से नहीं चलना होगा?
जर्नीमैन गीक

@JourneymanGeek तुम शायद सही हो। uniq -cयह भी अच्छी तरह से स्वरूपित उत्पादन प्राप्त करने का एक बेहतर तरीका की तरह लगता है। मैं नो * निक्स गुरु हूं, ऊपर मैं सिर्फ वही है जो मैंने अपने सीमित ज्ञान और कुछ आदमी पृष्ठों से एक साथ लाने में कामयाब रहा :)
Indrek

तो क्या मैंने, पी, और मेरे एक असाइनमेंट में लगभग 5000 एड्रेस बुक प्रविष्टियों के माध्यम से पिछले कार्यकाल को शामिल किया, और यूनीक ने इसे बहुत आसान बना दिया।
जर्नीमैन गीक

7

22hgp10a.txt के अनुक्रम रेखाओं का उपयोग करके grep और awk के बीच के समय के अंतर को मेरे सिस्टम पर जाने के लिए awk का उपयोग करके बनाते हैं ...

[संपादित करें]: डेव के संकलित समाधान को देखने के बाद जागना भी भूल जाते हैं, क्योंकि पूर्ण फ़ाइल संवेदनशील गणना के लिए इस फ़ाइल पर उनकी ०.१ सेकंड में पूरी हो जाती है।

# A nice large sample file.
wget http://gutenberg.readingroo.ms/etext02/22hgp10a.txt

# Omit the regular text up to the start `>chr22` indicator.
sed -ie '1,/^>chr22/d' 22hgp10a.txt

sudo test # Just get sudo setup to not ask for password...

# ghostdog74 answered a question <linked below> about character frequency which
# gave me all case sensitive [ACGNTacgnt] counts in ~10 seconds.
sudo chrt -f 99 /usr/bin/time -f "%E elapsed, %c context switches" \
awk -vFS="" '{for(i=1;i<=NF;i++)w[$i]++}END{for(i in w) print i,w[i]}' 22hgp10a.txt

# The grep version given by Journeyman Geek took a whopping 3:41.47 minutes
# and yielded the case sensitive [ACGNT] counts.
sudo chrt -f 99 /usr/bin/time -f "%E elapsed, %c context switches" \
grep -o foo.text -e A -e T -e C -e G -e N -e -|sort|uniq -c

भूत के मामले का असंवेदनशील संस्करण ~ 14 सेकंड में पूरा हुआ।

इस प्रश्न के स्वीकृत उत्तर में सेड को समझाया गया है ।
बेंचमार्किंग इस प्रश्न के स्वीकृत उत्तर की तरह है । इस सवाल पर
ghostdog74 द्वारा स्वीकृत उत्तर था ।


1
आप s/cache[letters[x]]/cache[letters[x]]+cache[toupper(letters[x])]इसकी गति को प्रभावित किए बिना इसे असंवेदनशील बनाने के लिए मेरा प्रयास कर सकते हैं ।
डेव

6

मुझे लगता है कि किसी भी सभ्य कार्यान्वयन से बचा जाता है। लेकिन क्योंकि यह सब कुछ 4 बार पढ़ने के लिए बुरा विचार है, मुझे लगता है कि कोई व्यक्ति किसी तरह से एक धारा उत्पन्न कर सकता है जो 4 फिल्टर के माध्यम से जाता है, प्रत्येक चरित्र के लिए एक, जिसे फ़िल्टर किया जाता है और जहां धारा की लंबाई भी किसी तरह से गणना की जाती है।

time cat /dev/random | tr -d -C 'AGCTN\-' | head -c16M >dna.txt
real    0m5.797s
user    0m6.816s
sys     0m1.371s

$ time tr -d -C 'AGCTN\-' <dna.txt | tee >(wc -c >tmp0.txt) | tr -d 'A' | 
tee >(wc -c >tmp1.txt) | tr -d 'G' | tee >(wc -c >tmp2.txt) | tr -d 'C' | 
tee >(wc -c >tmp3.txt) | tr -d 'T' | tee >(wc -c >tmp4.txt) | tr -d 'N' | 
tee >(wc -c >tmp5.txt) | tr -d '\-' | wc -c >tmp6.txt && cat tmp[0-6].txt

real    0m0.742s
user    0m0.883s
sys     0m0.866s

16777216
13983005
11184107
8387205
5591177
2795114
0

संचयी रकम तब tmp [0-6] .txt में होती है, इसलिए काम अभी भी जारी है

इस दृष्टिकोण में केवल 13 पाइप हैं, जो 1 एमबी से कम मेमोरी में कनवर्ट करता है।
बेशक मेरा पसंदीदा समाधान है:

time cat >f.c && gcc -O6 f.c && ./a.out
# then type your favourite c-program
real    0m42.130s

यह एक बहुत अच्छा उपयोग है tr
adavid

4

मुझे इसके बारे में uniqन तो पता था और न ही grep -o, लेकिन चूंकि @JourneymanGeek और @ crazy2be पर मेरी टिप्पणियों को इस तरह का समर्थन मिला था, शायद मुझे इसे अपने स्वयं के एक अन्वेषक में बदल देना चाहिए:

यदि आप जानते हैं कि आपकी फ़ाइल में केवल "अच्छे" अक्षर हैं (जिन्हें आप गिनना चाहते हैं), तो आप जा सकते हैं

grep . -o YourFile | sort | uniq -c

यदि केवल कुछ वर्णों की गणना की जानी चाहिए और अन्य नहीं (अर्थात विभाजक)

grep '[ACTGN-]' YourFile | sort | uniq -c

पहले वाला नियमित अभिव्यक्ति वाइल्डकार्ड का उपयोग करता है ., जो किसी भी एकल वर्ण से मेल खाता है। दूसरा एक एक कोई विशेष क्रम के साथ 'स्वीकार कर लिया पात्रों में से set', का उपयोग करें, सिवाय इसके कि -पिछले आना चाहिए ( A-C'के बीच किसी भी चरित्र के रूप में व्याख्या की है Aऔर C)। उस मामले में उद्धरण की आवश्यकता होती है ताकि आपका शेल एकल-वर्ण फ़ाइलों की जांच करने के लिए विस्तार करने की कोशिश न करे यदि कोई हो (और "कोई मैच नहीं" त्रुटि उत्पन्न करता है यदि कोई नहीं)।

ध्यान दें कि "सॉर्ट" में एक -uनीच झंडा भी है ताकि यह केवल एक बार चीजों को रिपोर्ट करे, लेकिन डुप्लिकेट को गिनने के लिए कोई साथी ध्वज नहीं है, इसलिए uniqवास्तव में अनिवार्य है।


-यदि आप इसे एक बैकस्लैश के साथ बचते हैं तो अंतिम समय तक नहीं आना '[A\-CTGN]'चाहिए : बस ठीक काम करना चाहिए।
Indrek

2

एक मूर्ख व्यक्ति:

tr -cd ATCGN- | iconv -f ascii -t ucs2 | tr '\0' '\n' | sort | uniq -c
  • tr-dसभी वर्णों को हटाने के लिए ( लेकिन -c) ATCGN-
  • iconv ucs2 (UTF16 को 2 बाइट तक सीमित) में परिवर्तित करने के लिए हर बाइट के बाद 0 बाइट जोड़ें,
  • दूसरा trउन एनयूएल पात्रों को एनएल में अनुवाद करने के लिए। अब हर किरदार अपनी लाइन पर है
  • sort | uniq -cप्रत्येक यूनीक लाइन को गिनने के लिए

यह गैर-मानक (GNU) -ogrep विकल्प का विकल्प है।


क्या आप यहां आज्ञाओं और तर्क का संक्षिप्त विवरण दे सकते हैं?
एंड्रयू लैंबर्ट

2
time $( { tr -cd ACGTD- < dna.txt | dd | tr -d A | dd | tr -d C | dd | tr -d G |
dd | tr -d T | dd | tr -d D | dd | tr -d - | dd >/dev/null; } 2>tmp ) &&
grep byte < tmp | sort -r -g | awk '{ if ((s-$0)>=0) { print s-$0} s=$0 }'

आउटपुट स्वरूप सबसे अच्छा नहीं है ...

real    0m0.176s
user    0m0.200s
sys     0m0.160s
2069046
2070218
2061086
2057418
2070062
2052266

संचालन का सिद्धांत:

  • $ ({कमांड | कमांड} 2> tmp) एक अस्थायी फ़ाइल में स्ट्रीम के stderr को पुनर्निर्देशित करता है ।
  • dd स्टडआउट के लिए स्टडिन आउटपुट करता है और स्टडर को दिए गए बाइट्स की संख्या को आउटपुट करता है
  • tr -d एक समय में एक वर्ण को फ़िल्टर करता है
  • grep और सॉर्ट अवरोही क्रम में dd के आउटपुट को फ़िल्टर करता है
  • awk अंतर की गणना करता है
  • dd के उदाहरणों से बाहर निकलने के क्रम की अनिश्चितता को संभालने के लिए सॉर्ट का उपयोग केवल पोस्ट-प्रोसेसिंग स्टेज में किया जाता है

गति 60 एमबीपीएस + लगती है


सुधार: tmp से छुटकारा? शामिल पत्र को प्रिंट करने के लिए 'पेस्ट' का उपयोग करें?
अकी सुहाइकोनें

1

नमूना फ़ाइल:

$ cat file
aix
unix
linux

कमान:

$ sed 's/./&\n/g' file | awk '!/^$/{a[$0]++}END{for (i in a)print i,a[i];}'
u 2
i 3
x 3
l 1
n 2
a 1

-1 स्पष्टता की कमी के लिए, और स्पष्टीकरण के बिना एक-लाइनर पोस्ट करने के लिए। AFAIK, यह एक कांटा बम हो सकता है
PPC

1

कुछ दूसरों को मिलाकर

chars='abcdefghijklmnopqrstuvwxyz-'
grep -o -i "[$chars]" foo|sort | uniq -c

| sort -nrआवृत्ति के क्रम में परिणाम देखने के लिए जोड़ें ।


1

संक्षिप्त जवाब:

यदि परिस्थितियाँ अनुमति देती हैं, तो कम वर्ण सेट की फ़ाइल आकारों की तुलना करें, जिसमें कोई भी ऐसा चरित्र न हो, जिसमें ऑफसेट हो और बस बाइट्स की गिनती हो।

आह, लेकिन पेचीदा विवरण:

वे सभी अस्सी के पात्र हैं। एक बाइट प्रति। निश्चित रूप से ओएस और ऐप को बनाने वाले सामानों की एक किस्म के लिए अतिरिक्त मेटाडेटा तैयार किया गया है। ज्यादातर मामलों में मैं अपेक्षा करता हूं कि मेटाडेटा की परवाह किए बिना अंतरिक्ष में समान मात्रा में ले जाएं, लेकिन मैं समान परिस्थितियों को बनाए रखने की कोशिश करूंगा जब आप पहली बार दृष्टिकोण का परीक्षण करेंगे और फिर सत्यापित करेंगे कि आपके पास इसके बारे में चिंता न करने से पहले एक निरंतर ऑफसेट है। अन्य गोचा यह है कि लाइन-ब्रेक में आमतौर पर दो एसेसी सफेद स्थान वर्ण शामिल होते हैं और कोई भी टैब या स्थान एक-एक होता है। यदि आप निश्चित हैं कि ये मौजूद रहेंगे और यह जानने का कोई तरीका नहीं है कि पहले से कितने हैं, तो मैं अब पढ़ना बंद कर दूंगा।

यह बहुत सारी बाधाओं की तरह लग सकता है, लेकिन अगर आप उन्हें आसानी से स्थापित कर सकते हैं, तो यह मुझे सबसे आसान / सबसे अच्छा प्रदर्शन करने के दृष्टिकोण के रूप में प्रभावित करता है यदि आपके पास इनमें से एक टन देखने के लिए है (जो संभावना है कि अगर यह डीएनए है)। लंबाई के लिए फ़ाइलों की एक टन की जाँच करना और एक निरंतर घटाना हर एक पर grep (या समान) चलाने की तुलना में तेजी से होगा।

अगर:

  • ये शुद्ध पाठ फ़ाइलों में सरल अखंड स्ट्रिंग्स हैं
  • वे समान फ़ाइल प्रकारों में हैं जो एक ही वेनिला नॉन-फॉर्मेटिंग टेक्स्ट-एडिटर द्वारा बनाई गई हैं जैसे कि स्काइट (चिपकाना ठीक है जब तक आप रिक्त स्थान / रिटर्न के लिए जांचते हैं) या कोई मूल प्रोग्राम जो किसी ने लिखा है

और दो चीजें जो शायद नहीं, लेकिन मैं पहले के साथ परीक्षण करूंगा

  • फ़ाइल नाम समान लंबाई के हैं
  • फाइलें उसी निर्देशिका में हैं

निम्नलिखित करके परेशान होने की कोशिश करें:

एक खाली फ़ाइल की तुलना कुछ आसानी से मानव-गणना वाले वर्णों के साथ कुछ और वर्णों के साथ करें। यदि अन्य दो फाइलों में से खाली फाइल को घटाना आपको बाइट काउंट देता है जो कि मैच काउंट काउंट करता है, तो आप कर रहे हैं। फ़ाइल की लंबाई जांचें और उस खाली राशि को घटाएं। यदि आप मल्टी-लाइन फ़ाइलों का पता लगाने का प्रयास करना चाहते हैं, तो अधिकांश संपादक लाइन ब्रेक के लिए दो विशेष एक-बाइट वर्ण संलग्न करते हैं क्योंकि एक Microsoft द्वारा अनदेखा किया जाता है, लेकिन आपको कम से कम व्हाइट-स्पेस चार्ट के लिए grep करना होगा, इस स्थिति में आप यह सब grep के साथ भी कर सकते हैं।


1

हास्केल तरीका:

import Data.Ord
import Data.List
import Control.Arrow

main :: IO ()
main = interact $
  show . sortBy (comparing fst) . map (length &&& head) . group . sort

यह इस तरह काम करता है:

112123123412345
=> sort
111112222333445
=> group
11111 2222 333 44 5
=> map (length &&& head)
(5 '1') (4 '2') (3 '3') (2 '4') (1,'5')
=> sortBy (comparing fst)
(1 '5') (2 '4') (3 '3') (4 '2') (5 '1')
=> one can add some pretty-printing here
...

संकलन और उपयोग:

$ ghc -O2 q.hs
[1 of 1] Compiling Main             ( q.hs, q.o )
Linking q ...
$ echo 112123123412345 | ./q
[(1,'\n'),(1,'5'),(2,'4'),(3,'3'),(4,'2'),(5,'1')]%       
$ cat path/to/file | ./q
...

शायद बड़ी फ़ाइलों के लिए अच्छा नहीं है।


1

त्वरित पर्ल हैक:

perl -nle 'while(/[ATCGN]/g){$a{$&}+=1};END{for(keys(%a)){print "$_:$a{$_}"}}'
  • -n: इनपुट लाइनों पर Iterate करें, लेकिन उनके लिए कुछ भी प्रिंट न करें
  • -l: स्ट्रिप या ऐड लाइन अपने आप टूट जाती है
  • while: वर्तमान लाइन में आपके अनुरोधित प्रतीकों की सभी घटनाओं पर पुनरावृति
  • END: अंत में, परिणाम प्रिंट करें
  • %a: हैश जहाँ मान संग्रहीत हैं

वर्ण जो सभी में नहीं होते हैं उन्हें परिणाम में शामिल नहीं किया जाएगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.