Pregunta

Tengo datos que se ven así:

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

Lo que quiero hacer es

  1. Genere todas las combinaciones de elementos en part1 a través de partK
  2. Encuentre el producto de los elementos correspondientes en @prob .

Por lo tanto, al final esperamos obtener este resultado:

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

El problema es que el siguiente código mío lo hace codificando los bucles Dado que el número de partes de @homopol puede ser variado y grande (por ejemplo, ~ K = 50), necesitamos una forma flexible y compacta para obtener el mismo resultado. ¿Hay alguna? Estaba pensando en usar Algorithm :: Loops , pero no estoy seguro de cómo lograrlo.

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

        }
    }
}
¿Fue útil?

Solución

Recomendaría Set :: CrossProduct , que creará un iterador para obtener el producto cruzado de todos sus conjuntos. Debido a que utiliza un iterador, no necesita generar todas las combinaciones de antemano; más bien, rinde cada uno bajo demanda.

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

Recomendaría Set :: CrossProduct , que creará un iterador para obtener el producto cruzado de todos sus conjuntos. Debido a que utiliza un iterador, no necesita generar todas las combinaciones de antemano; más bien, rinde cada uno bajo demanda.

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

Recomendaría Set :: CrossProduct , que creará un iterador para obtener el producto cruzado de todos sus conjuntos. Debido a que utiliza un iterador, no necesita generar todas las combinaciones de antemano; más bien, rinde cada uno bajo demanda.

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

Recomendaría Set :: CrossProduct , que creará un iterador para obtener el producto cruzado de todos sus conjuntos. Debido a que utiliza un iterador, no necesita generar todas las combinaciones de antemano; más bien, rinde cada uno bajo demanda.

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

Recomendaría Set :: CrossProduct , que creará un iterador para obtener el producto cruzado de todos sus conjuntos. Debido a que utiliza un iterador, no necesita generar todas las combinaciones de antemano; más bien, rinde cada uno bajo demanda.

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

Recomendaría Set :: CrossProduct , que creará un iterador para obtener el producto cruzado de todos sus conjuntos. Debido a que utiliza un iterador, no necesita generar todas las combinaciones de antemano; más bien, rinde cada uno bajo demanda.

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

Otros consejos

Una solución que utiliza Algorithm :: Loops sin cambiar los datos de entrada se vería algo así :

use Algorithm::Loops;

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

Una solución que utiliza Algorithm :: Loops sin cambiar los datos de entrada se vería algo así :

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

Pero creo que realmente podría aclarar el código cambiando la estructura a una más como

<*>

porque sin las estructuras de datos paralelas simplemente puede iterar sobre las secuencias de base disponibles, en lugar de iterar sobre índices y luego buscar esos índices en dos lugares diferentes.

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

Pero creo que realmente podría aclarar el código cambiando la estructura a una más como

<*>

porque sin las estructuras de datos paralelas simplemente puede iterar sobre las secuencias de base disponibles, en lugar de iterar sobre índices y luego buscar esos índices en dos lugares diferentes.

¿Por qué no usas la recursividad? Pase la profundidad como parámetro y deje que la función se llame a sí misma con profundidad + 1 dentro del bucle.

podría hacerlo creando una matriz de indicadores de la misma longitud que la matriz @homopol (N say), para realizar un seguimiento de qué combinación está viendo. De hecho, esta matriz es como un número en la base N, siendo los elementos los dígitos. Itere de la misma manera que escribiría números consecutivos en la base N, por ejemplo (0 0 0 ... 0), (0 0 0 ... 1), ..., (0 0 0 ... N- 1), (0 0 0 ... 1 0), ....

Enfoque 1: Cálculo a partir de índices

Calcule el producto de longitudes en homopol (length1 * length2 * ... * lengthN). Luego, repita i desde cero hasta el producto. Ahora, los índices que desea son i% length1, (i / length1)% length2, (i / length1 / length2)% length3, ...

Enfoque 2: Recursión

Me golpearon, ver la respuesta de Nikie. :-)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top