كيف يمكنني إنشاء مجموعات من عدة قوائم دون hardcoding الحلقات ؟

StackOverflow https://stackoverflow.com/questions/1442965

  •  22-07-2019
  •  | 
  •  

سؤال

لدي البيانات التي تبدو مثل هذا:

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

ما أريد القيام به هو

  1. تولد كل مجموعات من العناصر في part1 من خلال partK
  2. العثور على المنتج من العناصر المقابلة في @prob.

ومن ثم في النهاية نحن نأمل في الحصول على هذا الناتج:

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

المشكلة هي أن البرمجية التالية لي هذا hardcoding الحلقات.منذ عدد من أجزاء @homopol هل يمكن أن تكون متنوعة و كبيرة (مثلا ، ~ك=50) ، نحن بحاجة المرنة والمدمجة طريقة للحصول على نفس النتيجة.هل هناك أي ؟ كنت أفكر في استخدام الخوارزمية::الحلقات, ولكن غير متأكد من كيفية تحقيق ذلك.

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

        }
    }
}
هل كانت مفيدة؟

المحلول

أنصح Set::CrossProduct, وهو ما سيخلق مكرر لانتاج منتج عبر كل مجموعات الخاصة بك.لأنه يستخدم التكرار, أنها لا تحتاج إلى توليد كل مجموعة في وقت مبكر ؛ بل ينتج كل واحد على الطلب.

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

نصائح أخرى

الحل باستخدام الخوارزمية::الحلقات دون تغيير إدخال البيانات سوف ننظر بشيء من مثل:

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

ولكن أعتقد أنك يمكن أن تجعل في الواقع رمز أكثر وضوحا عن طريق تغيير بنية واحدة مثل

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

لأنه من دون موازية هياكل البيانات يمكنك ببساطة تكرار عبر المتوفرة قاعدة تسلسل بدلا من بالتكرار على المؤشرات و من ثم البحث عن تلك المؤشرات في مكانين مختلفين.

لماذا لا يمكنك استخدام العودية?تمر عمق كمعلمة والسماح استدعاء دالة نفسها مع عمق+1 داخل الحلقة.

يمكنك القيام بذلك عن طريق إنشاء مجموعة من indicies نفس طول @homopol مجموعة (ن القول) ، لتتبع أي تركيبة كنت تبحث في.في الواقع هذه المجموعة هو مجرد مثل رقم في قاعدة N ، مع العناصر الأرقام.تكرار في نفس الطريقة كما لو كنت أكتب consectutive أرقام في قاعدة N, e.ز (0 0 0 ...0), (0 0 0 ...1), ...,(0 0 0 ...N-1), (0 0 0 ...1 0), ....

النهج 1:حساب من المؤشرات

حساب المنتج من الأطوال في homopol (length1 * length2 * ...* lengthN).ثم أعاد أنا من صفر إلى المنتج.الآن مؤشرات تريد وأنا % length1 ، (i / length1)%length2 ، (i / length1 / length2) % length3, ...

النهج 2:العودية

أنا حصلت على ضرب إلى ذلك ، نرى nikie الجواب.:-)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top