Слияние 2 файлов на основе отдельного столбца

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

У меня есть два разделенных от запятой файла различных длин, file1.csv и file2.csv.

Я должен объединить эти файлы на основе их первого поля. Если первое поле от file1.csv присутствует в file2.csv, затем соответствующая строка от file2.csv должен быть добавлен к тому из file1.csv. Если 1-е поле не присутствует, то строка от file1.csv должен быть распечатан и no match добавленный к нему.

file1.csv (4 столбца):

Contig_Spider_Gland_98_1_1,>Contig_Spider_Gland_98_1_1 [1169 - 963] (REVERSE SENSE),MQGHRRKLATPRQRAPRKERQRALLLRLQWRIGLQPCSRRNKSLDRKNIYWRYLVEYGSWKGRTHISDV,C#
Contig_Spider_Gland_98_7_3,>Contig_Spider_Gland_98_17965_1 [90 - 278],MADVEKTSCCTETKECCKDETCCENGQGACHTGKEECKDTCHKKACGCKAGEDCKCSDGKCGC,CC#CC#CC#C#C#C#C#C#C#C#C#C#

file2.csv (7 столбцов):

Contig_Spider_Gland_98_1_1, SignalP-4.1, SIGNAL, 1, 22, 0.808, YES
Contig_Spider_Gland_98_8_2, SignalP-4.1, SIGNAL 1, 20, 0.877, YES

Желаемый вывод:

Contig_Spider_Gland_98_1_1,>Contig_Spider_Gland_98_1_1 [1169 - 963] (REVERSE SENSE),MQGHRRKLATPRQRAPRKERQRALLLRLQWRIGLQPCSRRNKSLDRKNIYWRYLVEYGSWKGRTHISDV,C#,Contig_Spider_Gland_98_1_1, SignalP-4.1, SIGNAL, 1, 22, 0.808, YES
Contig_Spider_Gland_98_7_3,>Contig_Spider_Gland_98_17965_1 [90 - 278],MADVEKTSCCTETKECCKDETCCENGQGACHTGKEECKDTCHKKACGCKAGEDCKCSDGKCGC,CC#CC#CC#C#C#C#C#C#C#C#C#C#,no match
2
задан 12 October 2015 в 14:31

3 ответа

Это должно сделать это:

awk -F, -vOFS=, '(NR==FNR){a[$1]=$0; next}
                   {
                      if(a[$1]){print $0,a[$1]}
                      else{print $0,"no match"}
                   }' file2.csv file1.csv

Объяснение

  • awk -F, -vOFS=, : выполненный awk, установка входа (-F) и вывод (-vOFS=,) разделители полей к ,.
  • (NR==FNR){a[$1]=$0; next} : NR и FNR специальные переменные, которые означают текущий номер строки и текущий номер строки текущего файла соответственно. При передаче больше чем одного имени файла эти два будут равны только, в то время как первый файл читается. Так, это означает "при чтении первого файла сохраните каждую строку в массиве, ключ которого является первым полем и перемещением к следующей строке".
  • if(a[$1]){print $0,a[$1]} : мы находимся теперь во втором файле. Если 1-е поле текущей строки было также в 1-м файле, распечатайте текущую строку и строку из первого файла.
  • else{print $0,"no match"} : если 1-е поле не было в первом файле, распечатайте текущую строку и "никакое соответствие"

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

3
ответ дан 13 October 2015 в 00:31
  • 1
    @CarstenS, которым Это оказывается systemd-timesyncd (8) , синхронизировал мой минимальный system' s часы. Я hadn' t думал об этом и узнал полунесчастным случаем: grep -RPis '(?<!mou)ntp' /var/log показал эти 14 строк системного журнала , показав синхронизации времени от хоста, который, оказывается, имеет ntp на его имя. В ретроспективе, это имеет смысл, что таинственный сервис, я никогда не знал, что имел, была часть systemd. (Btw, положительная сторона у chrony, который я hadn' t проверенный на также; it' s не установленный, все же.) – Eliah Kagan 3 January 2017 в 05:09

Другой выбор состоит в том, чтобы использовать соединение:

join -t, file1.csv file2.csv -a 1 -o auto -e 'no match'

, Если входные файлы еще не сортированы, Вы можете сделать так сразу:

join -t, <(sort file1.csv) <(sort file2.csv) -a 1 -o auto -e 'no match'

Exlanation

  • -t, устанавливает полевой сепаратор
  • -a 1, гарантируют, что все unpairable линии напечатаны также
  • -o auto наборы, выходной формат
  • -e 'no match' заменяет недостающие поля ввода 'никаким матчем'
  • <(list), оператор соединяет продукцию команд вида к названным трубам, которые тогда используются в качестве файлов для команды соединения (названный Заменой Процесса)
0
ответ дан 13 October 2015 в 00:31

Это должно сделать (сократил (R) и зафиксировал (ТМ) terdon):

#!/usr/bin/perl

use strict;
use warnings;

@ARGV==2 || die;

open(my $file1, $ARGV[0]) || die("Could not open \"$ARGV[0]\": $!");
open(my $file2, $ARGV[1]) || die("Could not open \"$ARGV[1]\": $!");

$"=","; #" (this comment exists only to prevent syntax hilighting from breaking)

while(my $l1 = <$file1>) {
    chomp($l1);
    my @f1 = split(",", $l1);
    if(my $l2 = <$file2>) {
        chomp($l2);
        my @f2 = split(",", $l2);
        if($f1[0] eq $f2[0]) {
            print("@f1,@f2\n");
        }
        else {
            push(@f1, "no_match");
            seek($file2, -length($l2), 1);
            print("@f1\n");
        }
    }
    else {
        push(@f1, "no_match");
        print("@f1\n");
    }
}

close($file1);
close($file2);

exit;

Так как файлы отсортированы, "file1.csv" является надмножеством "file2.csv" и нет никаких дублирующихся строк ни в одном файлов это:

  • Сравнивает следующие строки в обоих файлах;
  • Если первое поле строки от "file1.csv" соответствует первому полю строки от "file2.csv", добавляет строку от "file2.csv" до строки от (разделенного от запятой) "file1.csv" и печатает сгенерированную строку; иначе добавляет "no_match" поле к строке от "file1.csv", возвращается одна строка в "file2.csv" и печатает измененную строку от "file1.csv";
  • Если "file2.csv" больше не имеет строк, добавляет "no_match" поле к строке от "file1.csv" и печатает измененную строку от "file1.csv".
1
ответ дан 13 October 2015 в 00:31
  • 1
    FTR Ctrl+Alt+PrintScreen поднимает экранную утилиту снимка на моей Беспроводной связи клавиатура Logitech K800. – WinEunuuchs2Unix 1 January 2017 в 16:31

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

Похожие вопросы: