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

Hi i am trying to find number of neighbors of an element in some arrays.i have a list in a file and i want to check them one by one trough some arrays and find neighbors.

#!/usr/bin/perl -w use strict; my @domains1=('PF05.3','PF11001.3','PF00389.24','PF10417.3'); my @domains2=('PF01','PF02','PF11001.3','PF00389'); my @domains3=('PF00389.24','PF05.3','PF01','PF00389'); my %h; my $element; open(INPUTDOMAINLIST,'<domainlist') or die "cannot open 'domainlist'becuase:$!"; chomp (my @list=<INPUTDOMAINLIST>); foreach my $domain(@list){ foreach $element(@domains1){ $element=$_; if($element=~/(\Q$domain\E/)){ my $i=indexarray("$element",@domains1); if($i==0){ $h{$element}=$domains1[1]; } elsif($i!=0 && $i<scalar(@domains1)-1){ $h{$element}=$domains1[$i-1]; $h{$element}=$domains1[$i+1]; } elsif($i==scalar(@domains1)-1){ $h{$element}=$domains1[$i-1]; } }} print " $h{$element}"; sub indexarray{ my $s=shift; $_ eq $s && return @_ while $_=pop; -1;}

Replies are listed 'Best First'.
Re: finding neighbors of an element in arrays
by GrandFather (Saint) on Jul 28, 2011 at 09:40 UTC

    I'm not sure what you are trying to do, but there are a number of obvious errors in your code.

    1. $element=$_; most likely sets $element to undef - $_ does not contain whatever you think it does
    2. $element used in foreach $element is not the same $element used in print " $h{$element}";. The value used with the hash is most likely undef.
    3. $h{$element}=$domains1[$i+1]; replaces the value from the $h{$element}=$domains1[$i-1]; assignment.

    If resolving the errors pointed out above doesn't fix your problem then you should show us a small sample of your input data and the output you expect from it. Maybe though you want to achieve something like:

    use strict; use warnings; my $list = <<LIST; PF10417.3 PF11001.3 PF05.3 LIST my @domains1 = ('PF05.3', 'PF11001.3', 'PF00389.24', 'PF10417.3'); my @domains2 = ('PF01', 'PF02', 'PF11001.3', 'PF00389'); my @domains3 = ('PF00389.24', 'PF05.3', 'PF01', 'PF00389'); my %neighbours; for my $domain (\@domains1, \@domains2, \@domains3) { for my $idx (0 .. $#$domain) { my @near = grep {$_ >= 0 && $_ <= $#$domain} $idx - 1, $idx + +1; push @{$neighbours{$domain->[$idx]}}, map {$domain->[$_]} @nea +r; } } open my $inList, '<', \$list or die "cannot open 'domainlist'becuase:$ +!"; while (defined (my $domain = <$inList>)) { chomp $domain; print "Domain $domain has neighbours: @{$neighbours{$domain}}\n"; }

    Prints:

    Domain PF10417.3 has neighbours: PF00389.24 Domain PF11001.3 has neighbours: PF05.3 PF00389.24 PF02 PF00389 Domain PF05.3 has neighbours: PF11001.3 PF00389.24 PF01
    True laziness is hard work

      thank you so much.it was great.but please give me some explanation about these lines of code.thank you again.

      for my $idx (0 .. $#$domain) { my @near = grep {$_ >= 0 && $_ <= $#$domain} $idx - 1, $idx + +1; push @{$neighbours{$domain->[$idx]}}, map {$domain->[$_]} @nea +r; } }

        The loop iterates over all the element indexes in the current domain array. For each index it generates a list containing the index before and after the current index: $idx - 1, $idx + 1. The grep then filters the list to give a list containing just valid indexes (it removes -1 or scalar @$domain values if present).

        That leaves the neighbour indexes for the current index in @near. The map turns the neighbour indexes into a list of neighbour values. The push pushes the list into the array referenced by the hash entry for the value at the current index.

        Looking back over that description I'm glad to be using Perl rather than COBOL!

        True laziness is hard work
Re: finding neighbors of an element in arrays
by Anonymous Monk on Jul 28, 2011 at 08:43 UTC

      for example PF05.3 has 3 neighbors in these three arrays ( PF11001.3, PF01,PF00389.24).or for example PF11001.3 has 3 neighbors (PF00389,PF02,PF05.3) and so on.out put is number of neighbors for each.thanks.

        And you just want the number? And this is a regular matrix without holes, i.e. all the arrays @domiansX have the same number of elements and no empty cells? Then all elements inside the matrix have 4 neighbors, all elements at the sides have 3 and all elements at the edge of the matrix have 2 neighbors.

        If your matrix has holes, you might preset each element to have 4 neighbors and subtract 1 from every neighbor of a hole

        PS: It might be easier to store the matrix as a two-dimensional array instead of having each row in a separate array. Check out perllol how to use two-dim arrays aka ArrayOfArrays

        Ok, misread your examples. But I still don't get it, why is PF00389.24 not a neighbor of PF11001.3 ? Maybe you could define neighborhood directly instead of using examples

Re: finding neighbors of an element in arrays
by JavaFan (Canon) on Jul 28, 2011 at 09:54 UTC
    Untested:
    my %targets = map {/(.*)/; ($1, 1)} <INPUTDOMAINLIST>; my @neighbours = @domain1[grep {$_ > 0 && $targets{$domain[$_-1]} || $ +_ < $#domain1 && $targets{$domain[$_+1]}} 0..$#domain];
    Alternatively, first calculate all the neighbours:
    my %neighbours; for (my $i = 0; $i < @domain1; $i++) { push @{$neighbours{$domain[$i]}}, $neighbours{$domain[$i-1]} if $i + > 0; push @{$neighbours{$domain[$i]}}, $neighbours{$domain[$i+1]} if $i + < $#domain1; } my @neighbours = map {@$_} @neighbours{map {/(.*)/; $1} <INPUTDOMAINLI +ST>};