5

別の質問で戻ってきました。私はデータのリストを持っています:

1 L DIELTQSPE H EVQLQESDAELVKPGASVKISCKASGYTFTDHE
2 L DIVLTQSPRVT H EVQLQQSGAELVKPGASIKDTY
3 A ALQLTQSPSSLSAS B RITLKESGPPLVKPTCS C ELDKWAN
4 A ALQLTQSPSSLSAS B RITLKESGPPLVKPTCS C ELDKWAG
5 A ALQLTQSPSSLSAS B RITLKESGPPLVKPTCS C LELDKWASL
6 L DIQMTQIPSSLSASLSIC H EVQLQQSGVEVKMSCKASGYTFTS
7 L SYELTQPPSVSVSPGSIT H QVQLVQSAKGSGYSFS P YNKRKAFYTTKNIIG
8 L SYELTQPPSVSVSPGRIT H EVQLVQSGAASGYSFS P NNTRKAFYATGDIIG
9 A MPIMGSSVAVLAIL B DIVMTQSPTVTI C EVQLQQSGRGP
10 A MPIMGSSVVLAIL B DIVMTQSPTVTI C EVQLQQSGRGP
11 L DVVMTQTPLQ H EVKLDESVTVTSSTWPSQSITCNVAHPASSTKVDKKIE
12 A DIVMTQSPDAQYYSTPYSFGQGTKLEIKR

そして、各行の3番目の要素&& 5番目の要素を比較し、同じ3番目の&&5番目の要素がある場合はそれらをグループ化します。たとえば、上記のデータを使用すると、結果は次のようになります。

3: 3 A ALQLTQSPSSLSAS B RITLKESGPPLVKPTCS C ELDKWAN
   4 A ALQLTQSPSSLSAS B RITLKESGPPLVKPTCS C ELDKWAG
   5 A ALQLTQSPSSLSAS B RITLKESGPPLVKPTCS C LELDKWASL
9: 9 A MPIMGSSVAVLAIL B DIVMTQSPTVTI C EVQLQQSGRGP
   10 A MPIMGSSVVLAIL B DIVMTQSPTVTI C EVQLQQSGRGP

Fyi、実際のデータでは、3番目、5番目、7番目の要素は非常に長いです。全体を見るためにカットさせました。

これは私がやったことです、それは非常に不器用であることを私は知っています、しかし初心者として、私は最善を尽くしています。そして問題は、それが「同じ」グループの最初のセットだけを表示することです。どこがうまくいかなかったのか、そして/またはこれを解決するための他の素敵な方法を教えていただけますか?

my $file = <>;
open(IN, $file)|| die "no $file: $!\n";
my @arr;
while (my $line=<IN>){
        push @arr, [split (/\s+/, $line)] ;
}
close IN;

my (@temp1, @temp2,%hash1);
for (my $i=0;$i<=$#arr ;$i++) {
    push @temp1, [$arr[$i][2], $arr[$i][4]]; 
    for (my $j=$i+1;$j<=$#arr ;$j++) {
        push @temp2, [$arr[$j][2], $arr[$j][4]];
        if (($temp1[$i][0] eq $temp2[$j][0])&& ($temp1[$i][1] eq $temp2[$j][1])) {
            push @{$hash1{$arr[$i][0]}}, $arr[$i], $arr[$j];
        }
    }
}
print Dumper \%hash1;
4

5 に答える 5

2

あなたはこれを必要以上に複雑にしすぎているように見えますが、それは初心者には一般的です。これを手動で行う方法について詳しく考えてください。

  • 各行を見てください。
  • 3番目と5番目のフィールドが前の行と同じであるかどうかを確認します。
  • もしそうなら、それらを印刷します。

ループとそれは完全に不要です:

#!/usr/bin/env perl

use strict;
use warnings;

my ($previous_row, $third, $fifth) = ('') x 3;

while (<DATA>) {
  my @fields = split;
  if ($fields[2] eq $third && $fields[4] eq $fifth) {
    print $previous_row if $previous_row;
    print "\t$_";
    $previous_row = '';
  } else {
    $previous_row = $fields[0] . "\t" . $_;
    $third = $fields[2];
    $fifth = $fields[4];
  }
}

__DATA__
1 L DIELTQSPE H EVQLQESDAELVKPGASVKISCKASGYTFTDHE
2 L DIVLTQSPRVT H EVQLQQSGAELVKPGASIKDTY
3 A ALQLTQSPSSLSAS B RITLKESGPPLVKPTCS C ELDKWAN
4 A ALQLTQSPSSLSAS B RITLKESGPPLVKPTCS C ELDKWAG
5 A ALQLTQSPSSLSAS B RITLKESGPPLVKPTCS C LELDKWASL
6 L DIQMTQIPSSLSASLSIC H EVQLQQSGVEVKMSCKASGYTFTS
7 L SYELTQPPSVSVSPGSIT H QVQLVQSAKGSGYSFS P YNKRKAFYTTKNIIG
8 L SYELTQPPSVSVSPGRIT H EVQLVQSGAASGYSFS P NNTRKAFYATGDIIG
9 A MPIMGSSVAVLAIL B DIVMTQSPTVTI C EVQLQQSGRGP
10 A MPIMGSSVAVLAIL B DIVMTQSPTVTI C EVQLQQSGRGP
11 L DVVMTQTPLQ H EVKLDESVTVTSSTWPSQSITCNVAHPASSTKVDKKIE
12 A DIVMTQSPDAQYYSTPYSFGQGTKLEIKR

(指定された出力で同じグループを取得するために、3番目のフィールドが9行目と一致するように、10行目を少し変更したことに注意してください。)

編集: 1行のコードがコピー/貼り付けエラーによって複製されました。

編集2:コメントに応えて、グループ化する必要のある行が連続していると想定しない2番目のバージョンを次に示します。

#!/usr/bin/env perl

use strict;
use warnings;

my @lines;
while (<DATA>) {
  push @lines, [ $_, split ];
}

# Sort @lines based on third and fifth fields (alphabetically), then on
# first field/line number (numerically) when third and fifth fields match
@lines = sort { 
  $a->[3] cmp $b->[3] || $a->[5] cmp $b->[5] || $a->[1] <=> $b->[1] 
} @lines;

my ($previous_row, $third, $fifth) = ('') x 3;
for (@lines) {
  if ($_->[3] eq $third && $_->[5] eq $fifth) {
    print $previous_row if $previous_row;
    print "\t$_->[0]";
    $previous_row = '';
  } else {
    $previous_row = $_->[1] . "\t" . $_->[0];
    $third = $_->[3];
    $fifth = $_->[5];
  }
}

__DATA__
1 L DIELTQSPE H EVQLQESDAELVKPGASVKISCKASGYTFTDHE
3 A ALQLTQSPSSLSAS B RITLKESGPPLVKPTCS C ELDKWAN
2 L DIVLTQSPRVT H EVQLQQSGAELVKPGASIKDTY
5 A ALQLTQSPSSLSAS B RITLKESGPPLVKPTCS C LELDKWASL
7 L SYELTQPPSVSVSPGSIT H QVQLVQSAKGSGYSFS P YNKRKAFYTTKNIIG
6 L DIQMTQIPSSLSASLSIC H EVQLQQSGVEVKMSCKASGYTFTS
9 A MPIMGSSVAVLAIL B DIVMTQSPTVTI C EVQLQQSGRGP
8 L SYELTQPPSVSVSPGRIT H EVQLVQSGAASGYSFS P NNTRKAFYATGDIIG
11 L DVVMTQTPLQ H EVKLDESVTVTSSTWPSQSITCNVAHPASSTKVDKKIE
10 A MPIMGSSVAVLAIL B DIVMTQSPTVTI C EVQLQQSGRGP
12 A DIVMTQSPDAQYYSTPYSFGQGTKLEIKR
4 A ALQLTQSPSSLSAS B RITLKESGPPLVKPTCS C ELDKWAG
于 2012-06-05T13:50:09.207 に答える
1

例:

use strict;
use warnings;

{ ... }

open my $fh, '<', $file or die "can't open $file: $!";

my %hash;

# read and save it
while(my $line = <$fh>){
    my @line = split /\s+/, $line;
    my $key = $line[2] . ' ' . $line[4];

    $hash{$key} ||= [];
    push @{$hash{$key}}, $line; 
}

# remove single elements
for my $key (keys %hash){
    delete $hash{$key} if @{$hash{$key}} < 2;
}

print Dumper \%hash;
于 2012-06-05T13:45:38.227 に答える
1

少し異なるアプローチ:

#!/usr/bin/perl

use strict;
use warnings;

my %lines; # hash with 3rd and 5th elements as key
my %first_line_per_group; # stores in which line a group appeared first

while(my $line = <>) {
    # remove line break
    chomp $line;

    # retrieve elements form line
    my @elements = split /\s+/, $line;

    # ignore invalid lines
    next if @elements < 5;

    # build key from elements 3 and 5 (array 0-based!)
    my $key = $elements[2] . " " . $elements[4];

    if(! $lines{key}) {
        $first_line_per_group{$key} = $elements[0];
    }

    push @{ $lines{$key} }, $line;
}


# output
for my $key (keys %lines) {
    print $first_line_per_group{$key} . ":\n";

    print "    $_\n" for @{ $lines{$key} };
}
于 2012-06-05T13:53:32.710 に答える
0

open()の3引数形式を使用する必要があり、データの読み取りを簡略化できます。

open my $fh, '<', $file
    or die "Cannot open '$file': $!\n";

chomp(my @rows = <$fh>);
@rows = map {[split]} @rows;

close $fh;

行をグループ化するには、3番目と5番目のフィールドを連結したハッシュをキーとして使用できます。編集:「異なる行が同じ連結を生成する場合」(Qtax)、無効な結果を排除するために区切り文字を追加する必要があります。個々のデータ行の数などの追加データは、ハッシュ値として格納できます。ここでは、行のフィールドが格納されています。

my %groups;
for (@rows) {
    push @{ $groups{$_->[2] . ' ' . $_->[4]} }, $_
        if @$_ >= 4;
}

単一の要素を整理します。

@{ $groups{$_} } < 2 && delete $groups{$_}
    for keys %groups;

挨拶、マティアス

于 2012-06-05T14:09:29.320 に答える
0

あなたのアプローチは、Perlのイディオムをかなりしっかりと理解していることを示しており、メリットがありますが、それでも私がそれを行う方法ではありません。

データの構造を少し変えると、これを簡単に利用できるようになると思います%hash1

(
    'ALQLTQSPSSLSAS' => {
        'RITLKESGPPLVKPTCS' => [3, 4, 5],
        'ABCXYZ' => [93, 95, 96],
    },
    'MPIMGSSVAVLAIL' => {
        'DIVMTQSPTVTI' => [9, 10],
    },
)

ABCXYZここで、データ構造を完全に表示するために、例にはないデータを追加しました。

于 2012-06-05T13:44:52.793 に答える