Объединение 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
1
задан 12 October 2015 в 14:31

2 ответа

Это должно быть сделано (сокращенное (R) и фиксированное (TM) by 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
ответ дан 23 May 2018 в 16:45

Другим вариантом является использование join:

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 [!d2 ] -t, устанавливает разделитель полей -a 1, чтобы гарантировать, что все распечатываемые строки также напечатаны. -o auto устанавливает выходной формат -e 'no match' заменяет отсутствующие поля ввода «нет соответствия», оператор <(list) подключает выход команд сортировки для именованных каналов, которые затем используются в качестве файлов для команды соединения (под названием «Замена процесса»)

0
ответ дан 23 May 2018 в 16:45
  • 1
    Здравствуй! Спасибо. Я не знал, что мы можем использовать соединение, даже если файлы не имеют одинаковой длины. – Trupti 19 October 2015 в 09:29

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

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