Frage

Ich habe Daten, die wie folgt aussieht:

    my @homopol = (
                   ["T","C","CC","G"],  # part1
                   ["T","TT","C","G","A"], #part2
                   ["C","CCC","G"], #part3 ...upto part K=~50
                  );


    my @prob = ([1.00,0.63,0.002,1.00,0.83],
                [0.72,0.03,1.00, 0.85,1.00],
                [1.00,0.97,0.02]);


   # Note also that the dimension of @homopol is always exactly the same with @prob.
   # Although number of elements can differ from 'part' to 'part'.

Was ich tun möchte, ist zu

  1. Generieren alle Kombinationen von Elementen in part1 durch aus partK
  2. , um ein Produkt der entsprechenden Elemente in @prob.

Damit am Ende hoffen wir, dass diese Ausgabe zu erhalten:

T-T-C  1 x 0.72 x 1 = 0.720
T-T-CCC     1 x 0.72 x 0.97 = 0.698
T-T-G  1 x 0.72 x 0.02 = 0.014
...
G-G-G  1 x 0.85 x 0.02 = 0.017
G-A-C  1 x 1 x 1 = 1.000
G-A-CCC     1 x 1 x 0.97 = 0.970
G-A-G  1 x 1 x 0.02 = 0.020

Das Problem ist, dass der folgende Code von mir tut, dass durch zu die Schleifen. Da die Anzahl der Teile @homopol werden kann, ist abwechslungsreich und groß (Z ~ K = 50), benötigen wir eine flexible und kompakte Art und Weise das gleiche Ergebnis zu erhalten. Gibt es irgendwelche? Ich dachte Algorithmus :: Loops , aber nicht sicher, wie das erreichen.

use strict;
use Data::Dumper;
use Carp;


my @homopol = (["T","C","CC","G"],
               ["T","TT","C","G","A"],
               ["C","CCC","G"]);


my @prob = ([1.00,0.63,0.002,1.00,0.83],
            [0.72,0.03,1.00, 0.85,1.00],
            [1.00,0.97,0.02]);



my $i_of_part1 = -1;
foreach my $base_part1 ( @{ $homopol[0] } ) {
    $i_of_part1++;
    my $probpart1 = $prob[0]->[$i_of_part1];

    my $i_of_part2 =-1;
    foreach my $base_part2 ( @{ $homopol[1] } ) {
        $i_of_part2++;
        my $probpart2 = $prob[1]->[$i_of_part2];

        my $i_of_part3 = -1;
        foreach my $base_part3 ( @{ $homopol[2] } ) {
            $i_of_part3++;
            my $probpart3 = $prob[2]->[$i_of_part3];

            my $nstr = $base_part1."".$base_part2."".$base_part3;
            my $prob_prod = sprintf("%.3f",$probpart1 * $probpart2 *$probpart3);

            print "$base_part1-$base_part2-$base_part3 \t";
            print "$probpart1 x $probpart2 x $probpart3 = $prob_prod\n";

        }
    }
}
War es hilfreich?

Lösung

Ich würde empfehlen, Set::CrossProduct , die einen Iterator schaffen, das Kreuz zu ergeben Produkt aller Ihrer Sets. Weil es einen Iterator verwendet, braucht es nicht jede Kombination im Voraus zu erzeugen; sondern es jeder auf Nachfrage ergibt.

use strict;
use warnings;
use Set::CrossProduct;

my @homopol = (
    [qw(T C CC G)],
    [qw(T TT C G A)],
    [qw(C CCC G)], 
);

my @prob = (
    [1.00,0.63,0.002,1.00],
    [0.72,0.03,1.00, 0.85,1.00],
    [1.00,0.97,0.02],
);

# Prepare by storing the data in a list of lists of pairs.
my @combined;
for my $i (0 .. $#homopol){
    push @combined, [];
    push @{$combined[-1]}, [$homopol[$i][$_], $prob[$i][$_]]
        for 0 .. @{$homopol[$i]} - 1;
};

my $iterator = Set::CrossProduct->new([ @combined ]);
while( my $tuple = $iterator->get ){
    my @h = map { $_->[0] } @$tuple;
    my @p = map { $_->[1] } @$tuple;
    my $product = 1;
    $product *= $_ for @p;
    print join('-', @h), ' ', join(' x ', @p), ' = ', $product, "\n";
}

Andere Tipps

Eine Lösung mit Algorithm :: Loops ohne die Eingabedaten ändern würde in etwa so aussehen :

use Algorithm::Loops;

# Turns ([a, b, c], [d, e], ...) into ([0, 1, 2], [0, 1], ...)
my @lists_of_indices = map { [ 0 .. @$_ ] } @homopol;

NestedLoops( [ @lists_of_indices ], sub {
  my @indices = @_;
  my $prob_prod = 1; # Multiplicative identity
  my @base_string;
  my @prob_string;
  for my $n (0 .. $#indices) {
    push @base_string, $hompol[$n][ $indices[$n] ];
    push @prob_string, sprintf("%.3f", $prob[$n][ $indices[$n] ]);
    $prob_prod *= $prob[$n][ $indices[$n] ];
  }
  print join "-", @base_string; print "\t";
  print join "x", @prob_string; print " = ";
  printf "%.3f\n", $prob_prod;
});

Aber ich denke, dass Sie tatsächlich der Code klarer durch Änderung der Struktur zu einer mehr wie

machen könnte
[ 
  { T => 1.00, C => 0.63, CC => 0.002, G => 0.83 },
  { T => 0.72, TT => 0.03, ... },
  ...
]

, weil ohne die parallelen Datenstrukturen Sie einfach über die zur Verfügung stehenden Basensequenzen laufen können, anstatt über Indizes iterieren und dann diese Indizes in zwei verschiedenen Stellen nach oben.

Warum nicht Rekursion verwenden? Übergeben der Tiefe als Parameter und lassen die Funktion selbst aufrufen mit der Tiefe + 1 innerhalb der Schleife.

Sie können es tun, indem eine Reihe von indicies die gleiche Länge wie die @homopol Arrays (N sagen), um zu verfolgen, welche Kombination Sie suchen auf. In der Tat ist dieses Array wie ein Zahl zur Basis N, mit den Elementen, die Ziffern zu sein. Iterate in der gleichen Art und Weise, wie Sie consectutive Zahlen in Basis N, zB (0 0 0 ... 0), (0 0 0 ... 1), ..., (0 0 0 ... würden aufschreiben N- 1), (0 0 0 ... 1 0), ....

Ansatz 1: Berechnung von Indizes

Berechnen Sie das Produkt der Längen in homopol (length1 * length2 * ... * lengthN). Dann iterieren i von Null bis zum Produkt. Nun werden die Indizes Sie sind i% length1, (i / length1)% length2, (i / length1 / length2)% Länge3, ...

Ansatz 2: Rekursion

habe ich mich daran geschlagen finden nikie Antwort. : -)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top