linux - मैं फ़ाइल में सभी संख्याओं को जल्दी से कैसे जोड़ सकता हूं?




perl bash (18)

पर्ल 6

say sum lines
~$ perl6 -e '.say for 0..1000000' > test.in

~$ perl6 -e 'say sum lines' < test.in
500000500000

मेरे पास एक फाइल है जिसमें कई हज़ार संख्याएं हैं, प्रत्येक अपनी लाइन पर है:

34
42
11
6
2
99
...

मैं एक स्क्रिप्ट लिखना चाहता हूं जो फ़ाइल में सभी संख्याओं के योग को मुद्रित करेगा। मुझे एक समाधान मिला है, लेकिन यह बहुत ही कुशल नहीं है। (इसे चलाने में कई मिनट लगते हैं।) मैं एक और अधिक कुशल समाधान की तलाश में हूं। कोई सुझाव?


अधिक संक्षेप में:

# Ruby
ruby -e 'puts open("random_numbers").map(&:to_i).reduce(:+)'

# Python
python -c 'print(sum(int(l) for l in open("random_numbers")))'

आप awk का उपयोग कर सकते हैं:

awk '{ sum += $1 } END { print sum }' file

एक पर्ल एक लाइनर के लिए, यह मूल रूप से वही बात है जो अयमान अनीह के जवाब में अजीब समाधान है:

 % perl -nle '$sum += $_ } END { print $sum'

यदि आप उत्सुक हैं कि पर्ल एक-लाइनर क्या करते हैं, तो आप उन्हें हटा सकते हैं:

 %  perl -MO=Deparse -nle '$sum += $_ } END { print $sum'

नतीजा कार्यक्रम का एक और वर्बोज़ संस्करण है, इस रूप में कि कोई भी कभी भी खुद को लिख नहीं पाएगा:

BEGIN { $/ = "\n"; $\ = "\n"; }
LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    $sum += $_;
}
sub END {
    print $sum;
}
-e syntax OK

बस गिगल्स के लिए, मैंने इसे 1,000,000 नंबर वाली फ़ाइल के साथ करने की कोशिश की (श्रेणी 0 - 9, 999 में)। मेरे मैक प्रो पर, यह लगभग तत्काल लौटता है। यह बहुत बुरा है, क्योंकि मैं उम्मीद कर रहा था कि mmap का उपयोग करना वास्तव में तेज़ होगा, लेकिन यह वही समय है:

use 5.010;
use File::Map qw(map_file);

map_file my $map, $ARGV[0];

$sum += $1 while $map =~ m/(\d+)/g;

say $sum;

बस मस्ती के लिए, पीडीएल , पर्ल के सरणी गणित इंजन के साथ ऐसा करते हैं!

perl -MPDL -E 'say rcols(shift)->sum' datafile

rcols कॉलम को एक मैट्रिक्स (इस मामले में 1 डी) में पढ़ता है और sum (आश्चर्य) मैट्रिक्स के सभी तत्वों को rcols है।


बस मस्ती के लिए, चलिए इसे बेंचमार्क करें:

$ for ((i=0; i<1000000; i++)) ; do echo $RANDOM; done > random_numbers

$ time perl -nle '$sum += $_ } END { print $sum' random_numbers
16379866392

real    0m0.226s
user    0m0.219s
sys     0m0.002s

$ time awk '{ sum += $1 } END { print sum }' random_numbers
16379866392

real    0m0.311s
user    0m0.304s
sys     0m0.005s

$ time { { tr "\n" + < random_numbers ; echo 0; } | bc; }
16379866392

real    0m0.445s
user    0m0.438s
sys     0m0.024s

$ time { s=0;while read l; do s=$((s+$l));done<random_numbers;echo $s; }
16379866392

real    0m9.309s
user    0m8.404s
sys     0m0.887s

$ time { s=0;while read l; do ((s+=l));done<random_numbers;echo $s; }
16379866392

real    0m7.191s
user    0m6.402s
sys     0m0.776s

$ time { sed ':a;N;s/\n/+/;ta' random_numbers|bc; }
^C

real    4m53.413s
user    4m52.584s
sys 0m0.052s

मैंने 5 मिनट के बाद सेड रन को निरस्त कर दिया


मुझे नहीं पता कि क्या आप पूरी फाइल के माध्यम से पढ़ने की जरूरत है, इस पर विचार करके आप इससे काफी बेहतर हो सकते हैं।

$sum = 0;
while(<>){
   $sum += $_;
}
print $sum;

मैं इसके लिए आर का उपयोग करना पसंद करता हूं:

$ R -e 'sum(scan("filename"))'

मैंने इसका परीक्षण नहीं किया है लेकिन इसे काम करना चाहिए:

cat f | tr "\n" "+" | sed 's/+$/\n/' | bc

यदि बीसी ईओएफ और ईओएल का इलाज नहीं करता है तो आपको बीसी (जैसे गूंज के माध्यम से) से पहले स्ट्रिंग में "\ n" जोड़ना पड़ सकता है ...


यह काम:

{ tr '\n' +; echo 0; } < file.txt | bc

यहाँ एक और लाइनर है

( echo 0 ; sed 's/$/ +/' foo ; echo p ) | dc

यह मानता है कि संख्या पूर्णांक हैं। यदि आपको दशमलव की आवश्यकता है, तो कोशिश करें

( echo 0 2k ; sed 's/$/ +/' foo ; echo p ) | dc

आवश्यक दशमलव की संख्या में 2 समायोजित करें।


यहां एक और है:

open(FIL, "a.txt");

my $sum = 0;
foreach( <FIL> ) {chomp; $sum += $_;}

close(FIL);

print "Sum = $sum\n";

सभी नई लाइनों को + से बदलना आसान नहीं है, 0 जोड़ें और Ruby दुभाषिया को भेजें?

(sed -e "s/$/+/" file; echo 0)|irb

यदि आपके पास irb नहीं है, तो आप इसे bc भेज सकते हैं, लेकिन आपको अंतिम ( echo ) को छोड़कर सभी न्यूलाइन को हटाना होगा। इसके लिए tr का उपयोग करना बेहतर है, जब तक कि आपके पास पीएचडी नहीं है।

(sed -e "s/$/+/" file|tr -d "\n"; echo 0)|bc

समाधान में से कोई भी अब तक paste उपयोग नहीं करता है। यहां एक है:

paste -sd+ filename | bc

उदाहरण के तौर पर, Σn की गणना करें जहां 1 <= n <= 100000:

$ seq 100000 | paste -sd+ | bc -l
5000050000

(उत्सुकता के लिए, seq n संख्याओं के अनुक्रम को 1 से n सकारात्मक संख्या प्रदान करेगा।)


हास्यास्पद होने के लिए:

cat f | tr "\n" "+" | perl -pne chop | R --vanilla --slave

jq का उपयोग करने का एक और विकल्प है:

$ seq 10|jq -s add
55

-s ( --slurp ) एक सरणी में इनपुट लाइनों को पढ़ता है।


cat nums | perl -ne '$sum += $_ } { print $sum'

(ब्रायन डी फोय के जवाब के समान, बिना 'अंत')


sed ':a;N;s/\n/+/;ta' file|bc







awk