Использование awk для определения количества идентичных столбцов

Использование awk для определения количества идентичных столбцов

У меня есть большое количество отдельных файлов, содержащих по шесть столбцов каждый (количество строк может варьироваться). Вот простой пример:

1   0   0   0   0   0

0   1   1   1   0   0

Я пытаюсь определить, сколько у меня уникальных столбцов (т.е. совпадают ли номера и их порядок), в данном случае это будет 3.

Есть ли простая однострочная команда для этого? Я знаю, что легко сравнить один столбец с другим, но как найти идентичные столбцы?

решение1

Вы можете посчитать уникальные столбцы с помощью следующей строки:

$ awk '{for (i=1; i<=NF; ++i) a[i]=a[i]$i; } END { for (i in a) print a[i] }' foo \
  | sort -u | wc -l

Команда awk транспонирует введенные вами данные, полученные строки сортируются, сохраняются только уникальные строки ( -u), а в конце подсчитываются все (уникальные) строки (т. е. транспонированные столбцы) ( wc -l).

Обратите внимание, что NFэто встроенная переменная awk, которая автоматически устанавливается на число полей в текущей записи. $iссылается на i-е поле и ENDохраняет следующий блок таким образом, что он выполняется после обработки всех записей. По умолчанию в Awk используется разделение полей пустыми-непустыми.

решение2

(((...))), но как найти одинаковые столбцы?

$ printf '%s\n' '1 0 0 0 0 0' '0 1 1 1 0 0' | awk -vSUBSEP='=' '
    { for (i=1; i<NF; i++)
        for (j=i+1; j<=NF; j++)
          if ($i==$j)
            M[i,j]++
    }
    END{ for (m in M) if (M[m]==NR) print m }'
5=6
2=3
2=4
3=4

Для всех столбцов i<jкаждой строки, инкрементировать M[i,j]всякий раз, когда значения этих столбцов равны. Так что M[i,j]==NRпосле чтения NRстрок означает, что значения были идентичны для всех прочитанных строк.

решение3

Этот вопрос меня заинтересовал, и я захотел следовать подходу, который я не мог точно понять, и получил замечательную помощь.после того, как я опубликовал другой вопрос. Вы можете понять подход, которому я пытаюсь следовать, из вопроса, который я опубликовал.

У меня есть еще 2 решения этой проблемы (одно изGnouc'sответ, который являетсяперлрешение и еще одно из Джонарешение, объединенное с моим решением).

#The variable appended_input will remove spaces/tabs and just append the rows. 
#Modify the file name in this line. Here I use inputfile as the filename. 

appended_input=$(column -s '\t' inputfile | tr -d '[:space:]') ;

#The array variable will store each column-wise value as an array element.  
#I use sort to find the number of unique elements.

array=($(
    for ((i=0; i<6; i++))
    do
        new=${appended_input:$i:1}
        for ((j=i+6; j<${#appended_input}; j=j+6))
        do 
            new="$new${appended_input:$j:1}"
        done
        echo "$new"
    done
    )) | echo "${array[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '

Тестирование

Мой входной файл выглядит следующим образом.

1 0 0 1 0 0
0 1 1 0 0 0
1 1 1 1 1 0
1 0 0 1 0 1
1 0 0 1 0 1

После запуска приведенного выше скрипта я получаю следующий вывод:

00011 00100 01100 10111

Вы можете использовать wc -wв качестве конечного канала и получить на выходе всего 4 вместо уникальных значений столбцов, как указано выше.

решение4

Вот gawkрешение, которое использует сопроцессы для подачи каждого столбца в отдельный экземпляр sha256sumи сообщает общее количество уникальных хешей (количество уникальных хешей должно совпадать с количеством уникальных столбцов, учитывая, что вероятность столкновения хешей с sha256sumстатистически незначима). Хотя некоторые могут посчитать это вопиющим хаком, одно из преимуществ этого подхода перед некоторыми другими заключается в том, что он не пытается конкатенировать/транспонировать данные и, следовательно, относительно эффективен в плане памяти.

awk 'BEGIN{for(i=1; i<=6; ++i){s=sprintf("%*s", i+1, ""); a[i]="sha256sum"s}}
    {for (i=1; i<=6; ++i) print $i |& a[i]}
    END{com= "sort | uniq | wc -l"
    for (i=1; i<=6; ++i){close(a[i], "to"); a[i] |& getline x;
    close(a[i]); print x | com};
    close(com)}' file 

Связанный контент