Как мне получить имена, содержащиеся в первом файле, которые не являются i?

Как мне получить имена, содержащиеся в первом файле, которые не являются i?

У меня есть два файла, содержащие миллиарды названий последовательностей ДНК, второй является подмножеством первого:

например,

1°:john mike anna paul laura .... 

2°:john mike paul ...

все имена занимают одну строку.

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

Спасибо вам всем!

решение1

Это очень просто сделать, но ваша жизнь станет намного проще, если у вас будет одно имя на строку вместо списка, разделенного пробелами. Существует множество отличных утилит для работы с текстовыми файлами в Linux, это одна из вещей, в которой все *nix'ы преуспевают, но большинство ожидают один элемент на строку. Поэтому большинство моих решений будут начинаться с соответствующей модификации файлов.

Измените имена файлов так, чтобы в каждой строке было по одному имени:

sed 's/ /\n/g' file > newfile

или, чтобы изменить исходный файл

sed -i 's/ /\n/g' file

Как только вы это сделаете, любой из этих вариантов даст вам то, что вы хотите:

  1. грэп

    $ grep -vFwf file2 file1
    anna
    laura
    
  2. commилиdiff

    $ comm -23 <(sort file1) <(sort file2)
    anna
    laura
    
    
    $ diff file1 file2 | grep -Po '<\s+\K.*'
    anna
    laura
    
  3. awk

    $ awk '(NR==FNR){a[$1]++; next}!($1 in a){print}' file2 file1 
    laura
    anna
    
  4. Перл

    $ perl -lne 'BEGIN{open(A,"file2"); while(<A>){chomp; $k{$_}++}} print unless $k{$_}' file2 file1
    laura
    anna
    

    или

    $ perl -lne '$k{$_}++; END{map{print unless $k{$_}>1}keys(%k)}' file2 file1
    laura
    anna
    

Если вы действительно не хотите менять формат файла (но на самом деле должны), вы можете сделать что-то вроде

awk '{for (i=1;i<=NF;i++){a[$i]++}}END{for(n in a){if(a[n]<2){print n}}}' file2 file1

или

perl -lane '$k{$_}++ for @F; END{map{print if $k{$_}<2} keys(%k)}' file1 file2

решение2

Если они отсортированы и разделены символами новой строки, вы можете использовать функцию, которая commпокажет вам строки, уникальные для file1:

comm -23 file1 file2

Демонстрация:

$ comm -23 <(echo -e 'john\nmike\nanna\npaul\nlaura'|sort) <(echo -e 'john\nmike\npaul'|sort)
anna
laura

Или вы можете diffсделать то же самое (поиск grepудаленных строк):

diff sorted-file-1 sorted-file-2 | grep -oP '(?<=< ).+'

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

file2 = {}
with open("file2") as f:
    for line in f:
        file2[line] = 0

with open("file1") as f:
    for line in f:
        if not line in file2:
            print line

Если что-то больше, то вам, возможно, захочется взглянуть на реальную базу данных и простой SQL. Они предназначены для больших данных.

решение3

И вариант Python: независимо от того, находятся ли все слова в одной строке или в отдельных строках:

#!/usr/bin/env python3

import sys

f1 = sys.argv[1]; f2 = sys.argv[2]

def read(f):
    with open(f) as content:
        return content.read().split()

for item in [w for w in read(f1) if not w in read(f2)]:
    print(item)

Скопируйте скрипт в пустой файл, сохраните его как showdiff.pyисполняемый и запустите командой:

/path/to/showdiff.py file1 file2

anna
laura

Примечание

Не вопрос, но слишком много взаимосвязано, чтобы упустить:

Если вам нужно перечислить различиявзаимно, (не только слова в , file1которые не встречаются в file2, но и слова в file2, которые не встречаются в file1), Следует использовать следующий сценарий:

#!/usr/bin/env python3

import sys

f1 = sys.argv[1]; f2 = sys.argv[2]

def read(f):
    with open(f) as content:
        return content.read().split()

wds1 = read(f1); wds2 = read(f2); allwords = wds1+wds2
for item in [w for w in allwords if (w in wds1, w in wds2).count(False) == 1]:
    print(item)

решение4

Если вы выберете вариант с Python, как предлагает Якоб Влийм, стоит использовать «set» (для получения дополнительной информации см.https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset). По сути, как только вы создали два множества, вы можете достичь математики множеств (объединение, пересечение, разность,...)
В этом случае разность множеств — это именно то, что вам нужно: новое множество со всеми элементами, которые есть в одном множестве и отсутствуют в другом.
Код от Jacob тогда будет таким:

#!/usr/bin/env python3

import sys

f1 = sys.argv[1]; f2 = sys.argv[2]

def read_set(f):
    with open(f) as content:
        return set(content.read().split())

for item in read_set(f1) - read_set(f2)]:
    print(item)

Конечно, для миллиардов записей это займет некоторое время... `

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