Необходимо сравнить значения в файле, где повторяется 1-й столбец - PullRequest
1 голос
/ 18 августа 2010

Итак, мой образец данных в следующем формате.

jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   18150   18354
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   19856   19974
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   21455   21638
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   21727   21897
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   21980   22063
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   24670   24811
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   34741   34902
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   3649    3836
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   59253   59409
jgi|Xentr4|100173|gw1.779.90.1  scaffold_779    101746  101969
jgi|Xentr4|100173|gw1.779.90.1  scaffold_779    106436  107233

и я пытаюсь сделать это для каждого уникального имени в первом столбце, получить минимальное значение для столбца 3 и максимальное значение для столбца 4. Таким образом, окончательный ввод будет выглядеть одинаково, файл с разделителями табуляции за исключением того, что у него будут первые 2 столбца для каждого уникального имени, тогда 3-й и 4-й столбцы будут минимальными и максимальными значениями, упомянутыми выше. Я довольно новичок в программировании и пытался сделать это с помощью хэшей, но с треском провалился. Я пытаюсь сейчас с массивами / регулярными выражениями, как показано ниже.

open (IN, "POS2") || die "nope\n";
my $prev_qn = super;
my $prev_sn = ultra;
my $prev_start = non;
my $prev_end = nono;
while (<IN>) {
    chomp;
    push (@list, "$_");
}
close (IN);
foreach $v (@list) {
    $info = $v;
    ($query_name, $scaf_num, $start, $end) = split(/\t/, $info);
    unless ($info =~ m/^$prev_qn/) {
        push @ready, $info;
        $prev_qn = $query_name;
        $prev_sn = $scaf_num;
        $prev_start = $start;
        $prev_end = $end;
    }
    else {
        if ($start < $prev_start) {
            splice(@ready,2,1,$start);
        }
        if ($end > $prev_end) {
            splice(@ready,3,1,$end);
        }
        $prev_qn = $query_name;
        $prev_sn = $scaf_num;
        $prev_start = $start;
        $prev_end = $end;
    }

    foreach $z (@ready) {
        print "$z\n";
    }
}

результат, который это возвращает, ниже.

jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   18150   18354
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   18150   18354
19974
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   18150   18354
19974
21638
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   18150   18354
19974
21638
21897
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   18150   18354
19974
21638
22063
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   18150   18354
19974
21638
24811
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   18150   18354
19974
21638
34902
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   18150   18354
19974
3649
34902
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   18150   18354
19974
3649
59409
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   18150   18354
19974
3649
101969

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

Ответы [ 3 ]

1 голос
/ 18 августа 2010

Вот один из способов сделать это.Просто укажите имя входного файла в качестве аргумента командной строки.Оператор <> откроет файл и предоставит строки для вашего скрипта.

use strict;
use warnings;

my %h;

while (my $line = <>){
    chomp $line;
    my ($k, $scaff, $mn, $mx) = split /\t/, $line;

    $h{$k} = { min => 9e99, max => -9e99 } unless exists $h{$k};

    $h{$k}{min} = $mn if $mn < $h{$k}{min};
    $h{$k}{max} = $mx if $mx > $h{$k}{max};
}

for my $k (sort keys %h){
    print join("\t", $k, $h{$k}{min}, $h{$k}{max}), "\n";
}

Я использую хэш-хэш для хранения минимальной и максимальной информации, потому что это делает код более декларативнымпотому что это гибкий.Например, предположим, вы решили, что вывод должен сохранить порядок первого появления любого имени из столбца 1. Просто добавьте еще один элемент в структуру hash-of-hashes, чтобы отслеживать номер строки ввода при каждом появлении имени:

$h{$k} = { min => 9e99, max => -9e99, line_n => $. } unless exists $h{$k};

Затем используйте эту новую информацию при сортировке вывода:

for my $k (sort { $h{$a}{line_n} <=> $h{$b}{line_n} } keys %h){
    # Same as above.
}
0 голосов
/ 20 августа 2010

Может делать следующее:

use FileHandle;

$file = new FileHandle "input_file";
@array = <$file>;
close $file;

%seen = ();

foreach (@array){
    ($col1,$col2,$col3,$col4) = split(/[\t\s]+/,$_);
    push(@newarray,$_) unless $seen{$col1}++;
}
print @newarray;
0 голосов
/ 18 августа 2010

Делает ли это то, что вы ищете?

open (IN, "POS2") || die "nope\n";
my %data;

# Read data line by line
while (<IN>)
{
    chomp;
    my @fields = split /\t/;

    # Note $fields[0] is the name by which we want to group.
    if (defined $data{$fields[0]})
    {
        # If there is already an entry for this name, update it
        $data{$fields[0]} = [
            $fields[1],
            $data{$fields[0]}[1] < $fields[2] ? $data{$fields[0]}[1] : $fields[2],
            $data{$fields[0]}[2] > $fields[3] ? $data{$fields[0]}[2] : $fields[3]
        ];
    }
    else
    {
        # Otherwise, create a new one
        $data{$fields[0]} = [ $fields[1], $fields[2], $fields[3] ];
    }
}
close (IN);

# Output one row for each group
foreach my $name (keys %data)
{
    my ($stuff, $min, $max) = @{$data{$name}};
    print "$name\t$stuff\t$min\t$max\n";
}

Я пробовал это, и это выводит это:

jgi|Xentr4|100173|gw1.779.90.1  scaffold_779    101746  107233
jgi|Xentr4|100164|gw1.1441.2.1  scaffold_1441   3649    59409

Это то, что вы хотели?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...