2017-01-27 2 views
0

Учитывая эту входная таблицу:Добавить частоту (число появлений) к моему столику текста через AWK

pac1 xxx 
pac1 yyy 
pac1 zzz 
pac2 xxx 
pac2 uuu 
pac3 zzz 
pac3 uuu 
pac4 zzz 

Мне нужно добавить частоты к третьему колонку, как это:

pac1 xxx 2/3 
pac1 yyy 1/3 
pac1 zzz 3/3 
pac2 xxx 2/2 
pac2 uuu 2/2 
pac3 zzz 2/2 
pac3 uuu 2/2 
pac4 zzz 3/1 

Где первый номер число вхождений во втором столбце.

awk '{print $2}' input | sort | uniq -c 

И число после косой черты Uniq вхождения первой колонки:

awk '{print $1}' input | sort | uniq -c 

Я хотел бы использовать реализацию в AWK.

EDIT:

Пожалуйста, измените выход - первый столбец имена, и мне нужно, чтобы подсчитать, сколько Uniq имен происходит в первой колонке, как:

pac1 xxx 2/4 
pac1 yyy 1/4 
pac1 zzz 3/4 
pac2 xxx 2/4 
pac2 uuu 2/4 
pac3 zzz 2/4 
pac3 uuu 2/4 
pac4 zzz 3/4 

Так Uniq имена только PAC1, PAC2 , pac3, pac4 => 4

Что-то вроде этого:

occur=$(awk '{print $1}' input | sort | wc -l) 

awk -v occur=$occur '{col2[$2]++} {print $0, col2[$2] "/" occur}' file 

Потенциальный как избежать переменной $.

ответ

7

Просто прочитайте файл дважды: первый пересчитывать значения и хранить их в массиве, а затем распечатать его значения:

$ awk 'FNR==NR {col1[$1]++; col2[$2]++; next} {print $0, col2[$2] "/" col1[$1]}' file file 
pac1 xxx 2/3 
pac1 yyy 1/3 
pac1 zzz 3/3 
pac2 xxx 2/2 
pac2 uuu 2/2 
pac3 zzz 3/2 
pac3 uuu 2/2 
pac4 zzz 3/1 

FNR==NR {things; next} трюк делать вещи только при чтении первого файла. Он основан на использовании FNR и NR: первый - полевой номер записи и последний номер записи. Это означает, что FNR содержит количество строк текущего файла, в то время как NR содержит количество строк, которые были прочитаны до сих пор в целом, что делает FNR==NR истинным только при чтении первого файла. Добавив next, мы пропустим текущую строку и перейдем к следующей.

Найти больше информации в Idiomatic awk.


Что касается вашего обновления: если вы хотите, последний элемент, чтобы содержать количество различных значений в первом столбце, просто проверить длину массива, который был создан. Это покажет вам много различных индексов, которые он содержит, и, следовательно, значение, которое вы хотите:

$ awk 'FNR==NR {col1[$1]++; col2[$2]++; next} {print $0, col2[$2] "/" length(col1)}' file file 
pac1 xxx 2/4 
pac1 yyy 1/4 
pac1 zzz 3/4 
pac2 xxx 2/4 
pac2 uuu 2/4 
pac3 zzz 3/4 
pac3 uuu 2/4 
pac4 zzz 3/4 
+0

спасибо, что поняли. Значит, это означает, что после 'next' awk чтение второго файла обработки? – Geroge

+1

@Geroge это трюк, чтобы прочитать только первый файл. Проверьте мое обновление с дополнительной информацией. – fedorqui

+0

спасибо, что это очень хорошо работает. Не могли бы вы добавить обновление для awk '{print $ 1}' | сортировать | uniq -c - это будет второе число. Вероятно, я могу пропустить сортировку, потому что отсортирован первый столбец. – Geroge

2

Если вы хотите использовать awk, то вам нужно будет проходить через каждую строку, и собрать некоторую информацию, используя три ассоциативные массивы. Один для сбора необработанных данных, один для подсчета экземпляров дублирования столбца 2, и один для подсчета экземпляров дублирования столбца 3. Затем введите END { for (item in data_array)}, который просматривает массив данных, разделяя поля, чтобы получить значения, используемые в качестве индексов для двух других массивов, и печатать каждую строку с соответствующей частотой. Что-то вроде:

awk '{ data[num++] = $0; 
     col1[$1]++; 
     col2[$2]++ 
    } 
    END { for (i = 0; i < num; i++) { 
     split(data[i], field) 
     printf "%s %d/%d\n", data[i], col2[field[2]], col1[field[1]] 
     } 
    }' < input.file 

Для этого требуется только чтение файла один раз, и может быть расширен для других столбцов и графов.Цикл for заставляет данные отображать тот же порядок, в котором он был собран.

Для получения информации об ассоциативных массивах, расщеплении строки и for обратитесь к man awk.

+0

Спасибо, Грег за это. Выглядит, это работа. Я сделал обновление для моего вопроса. Можно ли реализовать свое решение? – Geroge

+0

Я уверен, что сценарий, который я написал, может быть обновлен, чтобы только увеличивать массивы col1/col2 при определенных условиях, но, к сожалению, я не могу понять, каковы эти условия из письменного описания. Сожалею. –

+1

В дополнение к тому, чтобы хранить в два раза размер всего входного файла в памяти, любезно предоставленный 'data [$ 0] = $ 0', сохраняющий каждую строку как индекс, так и содержимое массива, и он бы скремблировал порядок на выходе любезно предоставлен оператором 'in'. Не сказать, что это плохо, просто, что ОР должен знать обо всех ситуациях. [@ fedorqui's answer] (http://stackoverflow.com/a/41897965/1745001) не имеет ни одной из этих проблем. –