Найдите общие элементы в конкретном столбце > 2 файлов и напечатайте соответствующие строки из каждого

мой вопрос является продолжением вопроса, заданного давным-давно. Вопрос заключался в том, чтобы найти общие элементы в> 2 файлах в Linux при сопоставлении записей в определенных столбцах.

Вопрос был (я имею в виду этот пост: найти общие элементы в> 2 файлах)

У меня есть три файла, как показано ниже

файл1.txt

"aba" 0 0 1
"abc" 0 1
"abd" 1 1 
"xxx" 0 0

файл2.txt

"xyz" 0 0
"aba" 0 0 0 1
"xxx" 0 0
"abc" 1 1

файл3.txt

"xyx" 0 0
"aba" 0 0 
"xxx" 0 0 0 1
"abc" 1 1

Я хочу найти похожие элементы во всех трех файлах на основе первых двух столбцов.

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

Примечание. Я ищу, чтобы сопоставлять элементы в столбце 1 только из всех файлов и последовательно печатать соответствующие строки из файлов.

Итак, в этом примере мой желаемый результат будет:

"xxx" 0 0 0 0 0 0 1
"aba" 0 0 1 0 0 0 1 0 0
"abc" 0 1 1 1 1 1 

где он печатает совпадающие элементы ($ 1) из файлов 1-3 последовательно.

Один пользователь предложил следующее решение:

awk '
    FNR == NR { 
        arr[$1,$2] = 1
        line[$1,$2] = line[$1,$2] ( line[$1,$2] ? SUBSEP : "" ) $0
        next
    }
    FNR == 1 { delete found }
    { if ( arr[$1,$2] && ! found[$1,$2] ) { arr[$1,$2]++; found[$1,$2] = 1 } }
    END { 
        num_files = ARGC -1 
        for ( key in arr ) {
            if ( arr[key] < num_files ) { continue }
            split( line[ key ], line_arr, SUBSEP )
            for ( i = 1; i <= length( line_arr ); i++ ) { 
                printf "%s\n", line_arr[ i ]
            } 
        } 
    }
' file1.txt file2.txt file3.txt

Однако это соответствует первым двум столбцам и печатает только всю строку из файла, который появляется первым в списке (здесь file1.txt)

Результат, который это дает:

"xxx" 0 0
"aba" 0 0 
"aba" 0 0 1

Есть ли способ изменить этот скрипт, чтобы он печатал совпадающие строки из всех файлов. Мне нужно, чтобы строки отображались рядом в формате, указанном выше. Мой файл разделен табуляцией, поэтому хотелось бы, чтобы вывод также был разделен табуляцией. Еще одним важным моментом является то, что все файлы содержат одинаковое количество столбцов, но различаются количеством строк.

Должен ли аба появляться дважды в ожидаемом результате?

Raman Sailopal 26.12.2020 11:57

На самом деле в моем файле элементы уникальны. В этом примере аба присутствует дважды, поэтому может возникнуть путаница. Если хотите, можете предположить, что я сравниваю первые два столбца, а все элементы в столбце 1 уникальны. Спасибо. Однако во втором столбце есть дубликаты, но первый столбец имеет приоритет.

David 26.12.2020 12:03

Более того, я думаю, что нет необходимости сравнивать элементы в столбце 2. Поскольку в моих файлах все значения столбца 1 уникальны, я могу просто сопоставить их между всеми файлами и отобразить строки из каждого файла, содержащие общие элементы.

David 26.12.2020 12:09

Так что, abc тоже не должно появляться?

Raman Sailopal 26.12.2020 12:09

Да, abc должен появиться, если я сопоставляю только первый столбец. В приведенном примере он соответствует первым двум столбцам, поэтому abc не появляется. Меня интересует сопоставление столбца 1. Я внесу необходимые изменения в исходный пост.

David 26.12.2020 12:14

Важен ли порядок выходных строк? Что определяет порядок?

Cyrus 26.12.2020 13:48

Нет, порядок вывода не важен. В приведенном примере порядок определяется файлом, который находится первым в списке. Но здесь это не имеет значения.

David 26.12.2020 14:18

@David: На самом деле в моем файле элементы уникальны. Пожалуйста, исправьте свои файлы примеров и выходные данные примеров, чтобы они отражали уникальные элементы. В противном случае ответы, которые вы получите, будут неправильными...

dawg 26.12.2020 14:35

Я изменил свои входные файлы, чтобы избежать путаницы.

David 26.12.2020 14:48

@David: Пожалуйста, также обновите вывод примера на основе этого

dawg 26.12.2020 14:48
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
10
160
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Данный:

$ head file?.txt
==> file1.txt <==
"aba" 0 0 1
"abc" 0 1
"abd" 1 1 
"xxx" 0 0

==> file2.txt <==
"xyz" 0 0
"aba" 0 0 0 1
"xxx" 0 0 0 1
"abc" 1 1

==> file3.txt <==
"xyx" 0 0
"aba" 0 1 0
"xxx" 0 0 0 1
"abc" 1 1

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

$ awk '{cnt[$1]++
     s = ""
     for (i=2;i<=NF;i++) s=s OFS $i
     seen[$1]= seen[$1] s}
     END{for (e in seen) if (cnt[e]>1) print e, seen[e]}' file?.txt

Отпечатки:

"aba"  0 0 1 0 0 0 1 0 1 0
"abc"  0 1 1 1 1 1
"xxx"  0 0 0 0 0 1 0 0 0 1

Из комментариев.

Данный:

$ head file{1..3}.txt
==> file1.txt <==
"aba" 0 0 1
"abc" 0 1
"abd" 1 1 
"xxx" 0 0

==> file2.txt <==
"xyz" 0 0
"aba" 0 0 0 1
"xxx" 0 0 0 1
"abc" 1 1

==> file3.txt <==
"xyx" 0 0
"xxx" 0 0 0 1
"abc" 1 1

(Примечание "aba" удалено в файле 3...)

Вы можете использовать этот awk:

$ awk 'FNR==1 {fcnt++} 
    {cnt[$1]++
    s = ""
    for (i=2;i<=NF;i++) s=s OFS $i
    seen[$1]= seen[$1] s}
    END{for (e in seen) if (cnt[e]==fcnt) print e, seen[e]}' file{1..3}.txt

Отпечатки:

"abc"  0 1 1 1 1 1
"xxx"  0 0 0 0 0 1 0 0 0 1

Эй, спасибо за ответ. Однако при запуске вашего сценария awk я получаю в качестве вывода: 0 1 0 1 0, 1 1 1 1 1, 0 0 0 1 0 0 0 Запятые предназначены для разделителей строк. По какой-то причине я не могу отформатировать раздел комментариев в формат кода

David 26.12.2020 14:42

Ваши файлы из Windows?

dawg 26.12.2020 14:46

Я работаю на машине с Windows, используя сервер на базе Linux через MobaXterm.

David 26.12.2020 14:52

Дополнительные переводы строки, вероятно, происходят из вашей среды. Они не исходят из сценария awk.

dawg 26.12.2020 14:54

Проблема решена. Каким-то образом каждая из моих строк имеет невидимый ^M, прикрепленный к конечному символу, который вызывал проблему.

David 26.12.2020 15:06
ЗДЕСЬ способ убрать лишние разделители строк в awk. Не могу проверить, потому что здесь нет компьютеров с Windows.
dawg 26.12.2020 15:30

Не могли бы вы изменить сценарий так, чтобы он печатал только строки, если элемент IFF n найден во всех файлах? Ваш скрипт отлично работает, но он печатает строки из файлов, даже если элемент совпадает только в 2-х файлах. В примере, который вы разработали, скажем, если «abc» отсутствует в файле 3.txt, вывод вообще не должен содержать abc. Здесь он по-прежнему будет печатать строки abc из файла1 и файла2.

David 26.12.2020 17:18

@ Дэвид, я не читал ваш вопрос, так как у вас уже есть принятый ответ, но похоже, что вы приняли ответ, который не делает то, что вы хотите, тем самым отговаривая кого-либо еще публиковать ответ, который может делать то, что вы хотите, и теперь надеюсь, что у того, кто опубликовал этот ответ, будет время / возможность изменить его, чтобы делать то, что вы хотите. Для будущих вопросов вы можете подождать, пока не получите 1 или несколько ответов, которые делают именно то, что вы хотите, прежде чем принять один из них.

Ed Morton 26.12.2020 18:24

@EdMorton: Честно говоря, он делает именно то, что он задал в вопросе. Если он хочет эту дополнительную функциональность, примеры и вопросы должны говорить об этом.

dawg 26.12.2020 18:32

@dawg а, так это Вопрос-хамелеон, и они должны задать новый дополнительный вопрос.

Ed Morton 26.12.2020 18:34

@ЭдМортон: точно

dawg 26.12.2020 18:39

@David: Насколько я понимаю, что вы ищете, я сделал эту модификацию.

dawg 26.12.2020 19:07

Другие вопросы по теме