Question

J'ai des données qui ressemblent à ceci:

    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'.

Ce que je veux faire, c'est

  1. Génère toutes les combinaisons d'éléments dans part1 via partK
  2. Recherchez le produit des éléments correspondants dans @prob .

Par conséquent, à la fin, nous espérons obtenir ce résultat:

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

Le problème est que mon code suivant le fait en codant en dur les boucles. Depuis le nombre de parties de @homopol est peut être varié et grand (par exemple ~ K = 50), nous avons besoin d’un moyen souple et compact d’obtenir le même résultat. Y a-t-il? Je pensais utiliser Algorithm :: Loops , mais je ne sais pas comment y parvenir.

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";

        }
    }
}
Était-ce utile?

La solution

Je recommanderais Set :: CrossProduct . , ce qui créera un itérateur pour donner le produit croisé de tous vos ensembles. Comme il utilise un itérateur, il n’est pas nécessaire de générer chaque combinaison à l’avance; chaque produit est plutôt à la demande.

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][

Je recommanderais Set :: CrossProduct . , ce qui créera un itérateur pour donner le produit croisé de tous vos ensembles. Comme il utilise un itérateur, il n’est pas nécessaire de générer chaque combinaison à l’avance; chaque produit est plutôt à la demande.

<*>], $prob[$i][

Je recommanderais Set :: CrossProduct . , ce qui créera un itérateur pour donner le produit croisé de tous vos ensembles. Comme il utilise un itérateur, il n’est pas nécessaire de générer chaque combinaison à l’avance; chaque produit est plutôt à la demande.

<*>]] for 0 .. @{$homopol[$i]} - 1; }; my $iterator = Set::CrossProduct->new([ @combined ]); while( my $tuple = $iterator->get ){ my @h = map {

Je recommanderais Set :: CrossProduct . , ce qui créera un itérateur pour donner le produit croisé de tous vos ensembles. Comme il utilise un itérateur, il n’est pas nécessaire de générer chaque combinaison à l’avance; chaque produit est plutôt à la demande.

<*>->[0] } @$tuple; my @p = map {

Je recommanderais Set :: CrossProduct . , ce qui créera un itérateur pour donner le produit croisé de tous vos ensembles. Comme il utilise un itérateur, il n’est pas nécessaire de générer chaque combinaison à l’avance; chaque produit est plutôt à la demande.

<*>->[1] } @$tuple; my $product = 1; $product *=

Je recommanderais Set :: CrossProduct . , ce qui créera un itérateur pour donner le produit croisé de tous vos ensembles. Comme il utilise un itérateur, il n’est pas nécessaire de générer chaque combinaison à l’avance; chaque produit est plutôt à la demande.

<*> for @p; print join('-', @h), ' ', join(' x ', @p), ' = ', $product, "\n"; }

Autres conseils

Une solution utilisant Algorithme :: Boucles sans modifier les données d'entrée ressemblerait beaucoup :

use Algorithm::Loops;

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

Une solution utilisant Algorithme :: Boucles sans modifier les données d'entrée ressemblerait beaucoup :

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

Mais je pense que vous pourriez réellement rendre le code plus clair en modifiant la structure en une autre comme

<*>

parce que sans les structures de données parallèles, vous pouvez simplement parcourir les séquences de base disponibles au lieu d’itérer sur des index, puis de les rechercher à deux endroits différents.

] } @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; });

Mais je pense que vous pourriez réellement rendre le code plus clair en modifiant la structure en une autre comme

<*>

parce que sans les structures de données parallèles, vous pouvez simplement parcourir les séquences de base disponibles au lieu d’itérer sur des index, puis de les rechercher à deux endroits différents.

Pourquoi n'utilisez-vous pas la récursivité? Passez la profondeur en tant que paramètre et laissez la fonction s’appeler avec la profondeur + 1 dans la boucle.

vous pouvez le faire en créant un tableau d’indices de la même longueur que le tableau @homopol (par exemple N), pour garder trace de la combinaison que vous regardez. En fait, ce tableau est comme un numéro en base N, les éléments étant les chiffres. Itérez de la même manière que vous noteriez des nombres consécutifs en base N, par exemple (0 0 0 ... 0), (0 0 0 ... 1), ..., (0 0 0 ... N- 1), (0 0 0 ... 1 0), ....

Approche 1: calcul à partir d'indices

Calcule le produit des longueurs dans homopol (longueur1 * longueur2 * ... * longueurN). Ensuite, itérez i de zéro au produit. Maintenant, les indices que vous souhaitez sont i% longueur1, (i / longueur1)% longueur2, (i / longueur1 / longueur2)% longueur3, ...

Approche 2: récursivité

Je me suis fait battre, voir la réponse de Nikie. : -)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top