Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi.

I am trying to solve for overlapping paths in perl.

For example if I have input

0-200 200-400 400-600 600-800 800-1000 1000-2000 0,1800

and I want to find all paths to reach from 0 to 2000, here would be

(0-200-400-600-800-1000-2000), (0-200-1800-2000), (0-1800-2000)

Can you please suggest a way to do this.

Thanks
Nean

<p> tags and Code tags added by GrandFather to improve readability

Replies are listed 'Best First'.
Re: search overlap paths
by GrandFather (Saint) on Jun 13, 2014 at 12:01 UTC

    A recursive search does the trick so long as run time on typical data is not an issue:

    use strict; use warnings; my @parts; while (<DATA>) { my ($start, $end) = /(\d+)\D(\d+)/; next if !defined $end; push @parts, [$start, $end]; } @parts = sort {$a->[0] <=> $b->[0] || $a->[1] <=> $b->[1]} @parts; print join ('-', @$_), "\n" for trailsBetween(0, 2000, @parts); sub trailsBetween { my ($prevEnd, $to, @parts) = @_; my @tails; return [$prevEnd] if $prevEnd == $to; while (@parts) { my ($start, $end) = @{shift @parts}; last if $start > $prevEnd; next if $end < $prevEnd; push @tails, trailsBetween($end, $to, @parts); } unshift @$_, $prevEnd for @tails; return @tails; } __DATA__ 0-200 0-1800 200-400 400-600 600-800 800-1000 1000-2000

    Prints:

    0-200-1800-2000 0-200-400-600-800-1000-2000 0-1800-2000
    Perl is the programming world's equivalent of English
Re: search overlap paths
by LanX (Saint) on Jun 13, 2014 at 02:03 UTC
    I'd put the pairs into a hash of arrays with start as key and end as values and then I'll search with a backtracking algorithm hopping from start to start.

    Best algorithm depends on many factors you didn't explained.

    • motivation
    • data size (speed matters?)
    • data source (unique starts?)
    FWIW: I'm pretty sure this can be solved with one of the graph modules.

    And last but not least: what did you try so far? (we are not to keen doing other peoples homework)

    Cheers Rolf

    (addicted to the Perl Programming Language)

      Hi Rolf. I tried putting a hash as you suggested. However for some of the paths the starts are the same while the end is different. Also I am new to graphs. Can you maybe direct me to a backtracking algorithm or graph module that will do this trick. I have tried answering your question below. motivation: This is not a homework. I am trying to stitch together alignments from strings. I know the start and end of the positions of the strings that i can recover from my data. And from this I have to generate the full string in the quickest way possible. data size: the data size can vary greatly depending on the size of my input string. data source: The starts are not unique. Even in my example, there are two chunks starting with 0 (0-200) and 90-1800). hope this answers your question
        Sorry I don't seem to understand your question.

        For instance there is no 1800-2000 link, such that your last two "solutions" don't make much sense to me.

        I'm only realizing it now because you didn't use any recommended formatting.

        And since you are posting anonymously, you can't correct it. :(

        Cheers Rolf

        (addicted to the Perl Programming Language)

Re: search overlap paths
by Cristoforo (Curate) on Jun 13, 2014 at 03:59 UTC
    I can't get an example running, (its late here), but I think to get all possible paths from the beginning number to the end number would involve a powerset. Something like if there are 8 numbers from lowest to highest, then you would need to generate the powerset of the 6 numbers between the highest and lowest numbers - 2^6 = 64 possible paths.

    List::PowerSet can do this for you.

    Here is a small program using the data you provided, (followed by the results of the run).

    #!/usr/bin/perl use strict; use warnings; use List::PowerSet qw(powerset); my $nums = '0-200 200-400 400-600 600-800 800-1000 1000-2000 0,1800'; my %hash; @hash{ split /\D+/, $nums } = (); my @sorted = sort {$a<=> $b} keys %hash; my $start = shift @sorted; my $end = pop @sorted; my $ps = powerset(@sorted); for my $set (@$ps) { print join("-", $start, @$set, $end), "\n"; } __END__ 0-200-400-600-800-1000-1800-2000 0-400-600-800-1000-1800-2000 0-200-600-800-1000-1800-2000 0-600-800-1000-1800-2000 0-200-400-800-1000-1800-2000 0-400-800-1000-1800-2000 0-200-800-1000-1800-2000 0-800-1000-1800-2000 0-200-400-600-1000-1800-2000 0-400-600-1000-1800-2000 0-200-600-1000-1800-2000 0-600-1000-1800-2000 0-200-400-1000-1800-2000 0-400-1000-1800-2000 0-200-1000-1800-2000 0-1000-1800-2000 0-200-400-600-800-1800-2000 0-400-600-800-1800-2000 0-200-600-800-1800-2000 0-600-800-1800-2000 0-200-400-800-1800-2000 0-400-800-1800-2000 0-200-800-1800-2000 0-800-1800-2000 0-200-400-600-1800-2000 0-400-600-1800-2000 0-200-600-1800-2000 0-600-1800-2000 0-200-400-1800-2000 0-400-1800-2000 0-200-1800-2000 0-1800-2000 0-200-400-600-800-1000-2000 0-400-600-800-1000-2000 0-200-600-800-1000-2000 0-600-800-1000-2000 0-200-400-800-1000-2000 0-400-800-1000-2000 0-200-800-1000-2000 0-800-1000-2000 0-200-400-600-1000-2000 0-400-600-1000-2000 0-200-600-1000-2000 0-600-1000-2000 0-200-400-1000-2000 0-400-1000-2000 0-200-1000-2000 0-1000-2000 0-200-400-600-800-2000 0-400-600-800-2000 0-200-600-800-2000 0-600-800-2000 0-200-400-800-2000 0-400-800-2000 0-200-800-2000 0-800-2000 0-200-400-600-2000 0-400-600-2000 0-200-600-2000 0-600-2000 0-200-400-2000 0-400-2000 0-200-2000 0-2000