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