2015-10-28 2 views
1

Я понял, как получить среднее файл, который содержит номера во всех линиях, таких как:AWK: Как печатать средние числа последовательных номеров в файле, но пропускать алфавитные символы/строки?

Numbers.txt

1 

2 

4 

8 

Выход:

Average: 3.75 

Это код, который я использую для этого:

awk '{ sum += $1; tot++ } END { print sum/tot; }' Numbers.txt 

Однако проблема заключается в том, что это не учитывает возможные строки, которые могут быть в файле. Например, файл, который выглядит следующим образом:

NumbersAndExtras.txt

1 

2 

4 

8 

Hello 

4 

5 

6 

Cat 

Dog 

2 

4 

3 

Для такого файла я хочу, чтобы напечатать несколько средних значений последовательных чисел, не обращая внимания на такие строки, что результат выглядит примерно так:

Выход:

Average: 3.75 

Average: 5 

Average: 3 

я мог придумать какой-то сложный код, может сделать это с помощью переменных и «if» операторов и циклов и еще много чего, но мне сказали, что это проще, чем при некоторых функциях awk. Я хотел бы знать, как это может выглядеть, а также объяснение того, почему это работает.

+1

существовала ли пустая строка в вашем входе? – cuonglm

+0

Я не принимал пустые строки во внимание, только строки, но я полагаю, что я тоже должен искать это. – user3624649

+0

Если ответ решает вашу проблему, пожалуйста, примите его, нажав на большую галочку (✓) рядом с ней. Если вы нашли другие ответы полезными, попробуйте их проголосовать. Ответы и ответы на голосование помогают не только тем, кто ответил, но и будущим читателям. См. [Соответствующую статью справочного центра] (http://stackoverflow.com/help/someone-answers). Если ваш вопрос еще не полностью ответил, пожалуйста, сообщите об этом. – mklement0

ответ

0

BEGIN запускается перед чтением первой строки из файла. Задайте сумму и количество 0.

awk 'BEGIN{ sum=0; count=0} {if (/[a-z][A-Z]/) { if (count > 0) {avg = sum/count; print avg;} count=0; sum=0} else { count++; sum += $1} } END{if (count > 0) {avg = sum/count; print avg}} ' NumbersAndExtras.txt 

Когда на линии есть алфавит, рассчитывайте и печатайте среднее значение.

И сделайте то же самое в блоке END, который запускается после обработки всего файла.

+0

Это что-то вроде того, что я делал, и мне сказали, как было сказано, что если я воспользуюсь некоторыми функциями awk, это может быть проще. Это то, что вы считаете самым простым кодом для этого? – user3624649

+0

Это самое простое, с чем я мог бы придумать. Я уверен, что есть awk-эксперты, которые могут придумать более простое и элегантное решение. –

0

Примечание: значение этого ответа в объясняет решение; другие ответы предлагают более лаконичные альтернативы.


Попробуйте следующее:

Обратите внимание, что это awkкоманда со сценарием, указанным в строке оболочки с многострочных буквальные - вы можете вставить все это в ваш терминала попробуй; в то время как можно втиснуть это в одну линию, это больно читаемость и способность комментировать:

awk ' 

# Define output function that prints an average. 
function printAvg() { print "Average: ", sum/count } 

# Skip blank lines 
NF == 0 { next}  

# Is the line non-numeric? 
/[[:alpha:]]/ { 
    # If this line ends a numeric block, print its 
    # average now and reset the variables to start the next group. 
    if (count) { 
     printAvg() 
     wasNum = sum = count = 0 
    } 
    # Skip to next line. 
    next 
    } 

    # Numeric line: set flag, sum, and increment counter. 
    { sum += $1; count++ } 

    # Finally: 
    END { 
    # If there is a group whose average has not been printed yet, 
    # do it now. 
    if (count) printAvg() 
    } 

' NumbersAndExtras.txt 

Если мы конденсироваться пропуски и полосы комментариев, мы до сих пор получить достаточно читаемый решение, до тех пор, мы по-прежнему использовать несколько строк:

awk ' 
function printAvg() { print "Average: ", sum/count } 
NF == 0 { next}  
/[[:alpha:]]/ { if (count) { printAvg(); sum = count = 0 } next } 
{ sum += $1; count++ } 
END { if (count) printAvg() } 
' NumbersAndExtras.txt 
0

еще один:

$ awk ' 
    function avg(s, c) { print "Average: ", s/c } 
    NF && !/^[[:digit:]]/ { if (count) avg(sum, count); sum = 0; count = 0; next} 
    NF { sum += $1; count++ } 
    END {if (count) avg(sum, count)} 
' <file 
+0

Вы не правильно обрабатываете последовательные строки без номера, поэтому ваш последний средний показатель будет '2.25', а не' 3'. Честно говоря, если вы исправите это, вы в конечном итоге восстановите мой ответ. – mklement0

+0

@ mklement0: мой плохой, отсутствует состояние. Еще нет, мой не использует дополнительный waNum var. – cuonglm

+0

Правда, это оптимизация, которую стоит сделать, но обратите внимание, что _generally_ (это не имеет значения для данных образца) более разумно использовать 'if (count)' как условие, так как вы могли бы иметь числовые блоки, содержащие только '0', строк или даже блоков, содержащих отрицательные числа, так что 'sum' заканчивается' 0', что приведет к пропущению средних значений. – mklement0

0

Держите его простой:

awk '/^$/{next} 
    /^[0-9]+/{a+=$1+0;c++;next} 
    c&&a{print "Average: "a/c;a=c=0} 
    END{if(c&&a){print "Average: "a/c}}' input_file 

Результаты:

Average: 3.75 
Average: 5 
Average: 3 
Смежные вопросы