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

Hi Monks, I need to convert a sequence containing the positions of 1's in a binary sequence into the binary sequence. For example, how can I convert the array @pos = (2,4,6,9) to the corresponding binary array @bin=(0,0,1,0,1,0,1,0,0,1) efficiently. Thanks in advance
  • Comment on sequence of positions to binary sequence

Replies are listed 'Best First'.
Re: sequence of positions to binary sequence
by FunkyMonk (Bishop) on Apr 16, 2009 at 08:24 UTC
    Assigning to an array slice gets you nearly what you want:

    @bin[@pos] = (1) x @pos; #(undef, undef, 1, undef, 1, undef, 1, undef, + undef, 1)

    That may be good enough, it depends on what you intend to do with @bin. To get the output you requested, follow the above with:

    $_ ||= 0 for @bin; #(0, 0, 1, 0, 1, 0, 1, 0, 0, 1)

    Update:

    Or, you could do the whole lot in reverse (given your revised spec):

    my @bin2 = (0) x 15; # assign 15 zeros @bin2[@pos] = (1) x @pos; # fill in the 1's
Re: sequence of positions to binary sequence
by citromatik (Curate) on Apr 16, 2009 at 08:21 UTC

    If you are seeking for efficiency, you may be interested in manage your binary array as a bit vector. See vec and unpack. There is also a Bit::Vector module, but I've never used it.

    citromatik

Re: sequence of positions to binary sequence
by gone2015 (Deacon) on Apr 16, 2009 at 08:24 UTC

    my @pos = (2,4,6,9) ; my $bits = '' ; foreach (@pos) { vec($bits, $_, 1) = 1 ; } ; ($bits = unpack('b*', $bits)) =~ s/0+$// ; my @bits = split(//, $bits) ; print "(", join(',', @bits), ")\n" ;
    ...when dealing with bit vectors vec is your friend, as are unpack/pack b/B and (occasionally) reverse.

Re: sequence of positions to binary sequence
by targetsmart (Curate) on Apr 16, 2009 at 09:23 UTC
    This will also keep you interested.
    perl -e '@arr=(2,4,6,9); vec($bits,$_,1) = 1 for (@arr); print unpack( +"b*",$bits),$/;'
    will output
    0010101001000000

    Vivek
    -- In accordance with the prarabdha of each, the One whose function it is to ordain makes each to act. What will not happen will never happen, whatever effort one may put forth. And what will happen will not fail to happen, however much one may seek to prevent it. This is certain. The part of wisdom therefore is to stay quiet.
Re: sequence of positions to binary sequence
by ELISHEVA (Prior) on Apr 16, 2009 at 09:05 UTC

    There has to be an easier way and there is:

    #just two lines my @bits= (0) x 15; $bits[$_] = 1 for @pos; #...and print the output print "<@bits>\n";

    outputs <0 0 1 0 1 0 1 0 0 1 0 0 0 0 0>.

    Best, beth

Re: sequence of positions to binary sequence
by Corion (Patriarch) on Apr 16, 2009 at 08:09 UTC

    To help us help you better, please show what code you've already written and how it fails to achieve your goal. Also, it helps if you describe to us in plain English what approach you try to create the "binary array".

    A simple approach to a solution would be to recognize that the "binary array" contains only zeroes except at the places given in @pos. As Perl doesn't conveniently handle infinite lists in most places, you have to find an upper bound for the "binary array" list after which it will only ever contain zeroes, to effectively convert the infinite list into a finite list.

      Sorry, I forgot to mention the length of the array. Lets say for the example it is 15. My first thought was to create an array of 15 zeros, then insert the 1's at the positions given in @pos. Simple, but I dont know how to simply create the array of zeros. Thanks
        but I dont know how to simply create the array of zeros

        Simple enough, see the "x" operator at perlop

        my @arr = (0) x 15

        citromatik

        I can think of many ways to fill an array with zeroes. For example, you could start with an empty array and put a zero at the first position. Once you have an array of zeroes of a given length, you can get an array with twice as many zeroes by appending the array to itself.

        What ideas have you come up with and what code have you written? This is not a site where we will do your homework for you. Most likely your course materials cover the knowledge necessary to master this task.

Re: sequence of positions to binary sequence
by Utilitarian (Vicar) on Apr 16, 2009 at 08:24 UTC
    Quick and dirty solution ahead.
    perl -e' @pos=qw(2 4 6 9); $max=0; for (0..(@pos -1)){ $bin[$pos[$_]]=1; $max=$pos[$_] if $max<$pos[$_]; } for (0..$max){ $bin[$_]=0 unless $bin[$_]; } print "@bin\n";'
    Update: This assumes that the largest index in @pos is the length of your @bin array, which would work if you only needed to test for true/false on the array, indeed if you only need to test true/false then the second loop is unneeded as undef and 0 are both false ;)

      Thanks to autovivification, the direct calculation of max is unnecessary. To create an array whose final element is at the maximum position of a 1:

      my @bits; $bits[$_] = 1 for @pos; for (0..($#bits-1)) { $bits[$_]=0 unless defined($bits[$_]); }

      Best, beth

        Doh!, thanks
Re: sequence of positions to binary sequence
by wol (Hermit) on Apr 16, 2009 at 17:07 UTC
    This feels like more of a C task than a perl task, so here's an answer in C-like perl...

    my @pos = (2,4,6,9); my $bin = 0; for (my $i = 0; $i < scalar @pos; $i++) { $bin |= 1 << $pos[$i]; } # Printing out the result is left as a follow-on exercise...

    --
    use JAPH;
    print JAPH::asString();

Re: sequence of positions to binary sequence
by youlose (Scribe) on Apr 17, 2009 at 05:11 UTC
    it's simple
    my @arr = (2,4,9); my @rslt; $rslt[$_]=1 for @arr; $_ or ($_ = 0) for @rslt; print "@rslt"; #0 0 1 0 1 0 0 0 0 1
Re: sequence of positions to binary sequence
by repellent (Priest) on Apr 16, 2009 at 16:41 UTC
    Course work? Length of 15 "bits"? Sure!
    > perl -e ' @pos = (2,4,6,9); for $i (0..14) { print --$| and --$| or next if grep { $_ == $i } @pos; print $|; }' 001010100100000
Re: sequence of positions to binary sequence
by bichonfrise74 (Vicar) on Apr 16, 2009 at 22:07 UTC
    How about this?
    #!/usr/bin/perl use strict; my @pos = qw( 2 4 6 9 ); my @bin; for (my $i = 0; $i < $pos[-1] + 1; $i++ ) { my $counter = 0; $counter = 1 if ( grep /$i/, @pos); push( @bin, $counter ); } print join ",", @bin;