У меня есть текстовый файл с 2 миллионами строк. Каждая строка имеет положительное целое число. Я пытаюсь сформировать вид таблицы частот вещи.
Входной файл:
3
4
5
8
Вывод должен быть:
3
7
12
20
Как я иду о выполнении этого?
С awk
:
awk '{total += $0; $0 = total}1'
$0
текущая строка. Так, для каждой строки я добавляю его к total
, установите строку на новое total
, и затем запаздывание 1
awk ярлык - он печатает текущую строку для каждого истинного условия, и 1
поскольку условие оценивает к истинному.
В Баш:
#! /bin/bash
file="YOUR_FILE.txt"
TOTAL=0
while IFS= read -r line
do
TOTAL=$(( TOTAL + line ))
echo $TOTAL
done <"$file"
Для печати частичных сумм целых чисел, данных по стандарту, вводит тот на строку:
#!/usr/bin/env python3
import sys
partial_sum = 0
for n in map(int, sys.stdin):
partial_sum += n
print(partial_sum)
, Если по некоторым причинам команда является слишком медленной; Вы могли использовать программу C:
#include <stdint.h>
#include <ctype.h>
#include <stdio.h>
int main(void)
{
uintmax_t cumsum = 0, n = 0;
for (int c = EOF; (c = getchar()) != EOF; ) {
if (isdigit(c))
n = n * 10 + (c - '0');
else if (n) { // complete number
cumsum += n;
printf("%ju\n", cumsum);
n = 0;
}
}
if (n)
printf("%ju\n", cumsum + n);
return feof(stdin) ? 0 : 1;
}
, Чтобы создать его и работать, введите:
$ cc cumsum.c -o cumsum
$ ./cumsum < input > output
UINTMAX_MAX
18446744073709551615
.
код C несколько раз быстрее, чем команда awk на моей машине для входного файла, сгенерированного:
#!/usr/bin/env python3
import numpy.random
print(*numpy.random.random_integers(100, size=2000000), sep='\n')
Вы, вероятно, хотите что-то вроде этого:
sort -n <filename> | uniq -c | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}'
Объяснение команды:
sort -n <filename> | uniq -c
виды вход и возвраты таблица частот | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}'
превращает вывод в более хороший Пример Формата :
Входной Файл list.txt
:
4
5
3
4
4
2
3
4
5
команда:
$ sort -n list.txt | uniq -c | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}'
Number Frequency
2 1
3 2
4 4
5 2
Простая острота Bash:
x=0 ; while read n ; do x=$((x+n)) ; echo $x ; done < INPUT_FILE
x
накопленная сумма всех чисел от текущей строки и выше.
n
число в текущей строке.
Мы циклично выполняемся по всем строкам n
из INPUT_FILE
и добавляем их числовое значение к нашей переменной x
и печать, которые суммируют во время каждого повторения.
Bash является немного медленным здесь, хотя, можно ожидать, что это будет обтекать 20-30 секунд для файла с 2 миллионами записей, не печатая вывод к консоли (который еще медленнее, независим от метода, который Вы используете).
Аналогично ответу @ steeldriver, но с немного менее загадочным bc
:
sed 's/.*/a+=&;a/' input | bc
Приятно, что в bc
(и dc
) есть калькуляторы произвольной точности, поэтому никогда не переполнится и не потеряет точность по сравнению с целыми числами.
Выражение sed
преобразует входные данные в:
a+=3;a
a+=4;a
a+=5;a
a+=8;a
Это затем оценивается с помощью bc
. Переменная a
bc автоматически инициализируется равной 0. Каждая строка увеличивает a
, а затем явно печатает ее.
В сценарии Python:
#!/usr/bin/env python3
import sys
f = sys.argv[1]; out = sys.argv[2]
n = 0
with open(out, "wt") as wr:
with open(f) as read:
for l in read:
n = n + int(l); wr.write(str(n)+"\n")
add_last.py
Выполните его с исходным файлом и предназначенным выходным файлом как аргументы:
python3 /path/to/add_last.py <input_file> <output_file>
Код довольно читаем, но подробно:
Открытый выходной файл для записи результатов
with open(out, "wt") as wr:
Открытый входной файл для чтения на строку
with open(f) as read:
for l in read:
Считайте строки, добавив значение новой строки к общему количеству:
n = n + int(l)
Запишите результат в выходной файл:
wr.write(str(n)+"\n")
Только для забавы
$ sed 'a+p' file | dc -e0 -
3
7
12
20
Это работает путем добавления +p
к каждой строке входа и затем передаче результата к dc
калькулятор, где
+ Pops two values off the stack, adds them, and pushes the result.
The precision of the result is determined only by the values of
the arguments, and is enough to be exact.
затем
p Prints the value on the top of the stack, without altering the
stack. A newline is printed after the value.
-e0
нажатия аргумента 0
на dc
стек для инициализации суммы.
Можно сделать это в энергии. Откройте файл и введите следующие нажатия клавиш:
qaqqayiwj@"<C-a>@aq@a:wq<cr>
Отметьте это <C-a>
на самом деле ctrl-a, и <cr>
возврат каретки, т.е. ввести кнопка.
Вот то, как это работает. Прежде всего мы хотим убрать регистр так, чтобы он не имел никаких побочных эффектов на первом разе через. Это просто qaq
. Затем мы делаем следующее:
qa " Start recording keystrokes into register 'a'
yiw " Yank this current number
j " Move down one line. This will break the loop on the last line
@" " Run the number we yanked as if it was typed, and then
<C-a> " increment the number under the cursor *n* times
@a " Call macro 'a'. While recording this will do nothing
q " Stop recording
@a " Call macro 'a', which will call itself creating a loop
После того, как этот рекурсивный макрос сделан, работая, мы просто звоним :wq<cr>
сохранить и выйти.
Острота Perl:
$ perl -lne 'print $sum+=$_' input.txt
3
7
12
20
С 2,5 миллионами строк чисел требуется приблизительно 6,6 секунд для обработки:
$ time perl -lne 'print $sum+=$_' large_input.txt > output.txt
0m06.64s real 0m05.42s user 0m00.09s system
$ wc -l large_input.txt
2500000 large_input.txt