http://www.perlmonks.org?node_id=1038101

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

Hi,

I am new to Perl (with no programming experience) so please bare with me. Problem: I am having issues making this work: Using a built-in function splice I need to remove a specified number of elements from the @_ array at once rather than the one-at-a-time that shift does

the original code was:

#!/usr/bin/perl use strict; use warnings; my @first = qw(Can unlock secret); my @second = qw(you the code?); my @mixed = interleave_words( scalar(@first), @first, @second ); print "Result: @mixed\n"; sub interleave_words { my @results; my $count = shift; foreach my $index ( 0 .. $count-1 ) { $results[$index * 2] = shift; } if ( @_ != $count ) { die "Second array not same size ($count) as the first\n"; } foreach my $index ( 0 .. $count-1 ) { $results[$index * 2 + 1] = shift; } return @results; }

I have changed the following code to meet the requirement below:

#!/usr/bin/perl use strict; use warnings; my @first = qw(Can unlock secret); my @second = qw(you the code?); my @mixed = interleave_words( scalar(@first), @first, @second ); print "Result: @mixed\n"; sub interleave_words { my @results; my $count = shift; foreach my $index ( 0 .. $count-1 ) { my @merge_list = splice (@_, 0, 2); # my @merge_list1 = splice (@merge_list, 0, 2+1); print "Result: @merge_list\n"; } if (@_!=$count) { die "Second array not same size ($count) as the first\n"; } return @results; }

but it is not working I am getting wrong output: I should be getting: Result: Can you unlock the secret code?

however I am getting: Result: Can Unlock Result: secret You Result: the Code? Second array not same size (3) as the first

Can someone help me out trying to figure out what I am doing wrong or missing out

Replies are listed 'Best First'.
Re: Using Splice with Two Arrays within a loop
by davido (Cardinal) on Jun 10, 2013 at 15:52 UTC

    I don't quite understand why you need a different approach to the same goal in your second snippet. I do think it's clever to have passed a count value for the first array as a way of dealing with the fact that Perl flattens lists, but references are built into the language, in part, to deal with that problem more conveniently. Passing a count is so... "C". ;)

    However, if I were doing it, I would just use List::MoreUtils "zip" function (also known as mesh):

    use List::MoreUtils qw( zip ); my @first = qw( can unlock secret ); my @second = qw( you the code? ); my @mixed = zip @first, @second; print "@mixed\n";

    Dave

      Hi,

      Sorry to clarify I have an assignment that requires the following to be done: "This program can be made both shorter and faster by using a built-in function named splice that will remove a specified number of elements from the @_ array at once, rather than the one-at-a-time that shift does." As you can see from my output I am doing something wrong. Can someone help me out. I need to use splice to resolve this.

      Thanks
Re: Using Splice with Two Arrays within a loop
by hbm (Hermit) on Jun 10, 2013 at 15:47 UTC

    You might find it easier by passing references to your arrays:

    #!/usr/bin/perl use strict; use warnings; my @first = qw(Can unlock secret); my @second = qw(you the code?); my @mixed = interleave_words( scalar(@first), \@first, \@second ); print "Result: @mixed\n"; sub interleave_words { my ($count, $first, $second) = @_; my @results; die unless $#$first == $#$second; return map { $$first[$_], $$second[$_] } 0..$count-1; }
      You might find it easier by passing references to your arrays ...

      But if you're going to do that, you might as well go all the way and dispense with the count argument altogether as mentioned by davido. In fact, this might actually be a good use for prototyping. Of course, if you use a prototype, you just end up with a version of  mesh() that is specialized for two arguments (easily generalized) and does array-size checking, which  mesh() doesn't. Still...

      >perl -wMstrict -le "use List::MoreUtils qw(mesh); use Data::Dump; ;; my @first = qw(Can unlock secret); my @second = qw(you the code?); ;; sub interleave_words (\@\@); ;; my @mixed = interleave_words(@first, @second); print qq{Result: '@mixed'}; ;; sub interleave_words (\@\@) { die 'array sizes differ' unless $#{$_[0]} == $#{$_[1]}; goto &mesh; } ;; my @ra = qw(a b c); my @rb = qw(1 2 ); dd [ mesh @ra, @rb ]; " Result: 'Can you unlock the secret code?' ["a", 1, "b", 2, "c", undef]

      (Note for anonymous OPer: Don't try this at school unless you really understand what's going on!)

      Hi, Sorry to clarify I have an assignment that requires the following to be done: "This program can be made both shorter and faster by using a built-in function named splice that will remove a specified number of elements from the @_ array at once, rather than the one-at-a-time that shift does." As you can see from my output I am doing something wrong. Can someone help me out. I need to use splice to resolve this. Thanks
        You're supposed to split the argument list into two with splice before the loop.
Re: Using Splice with Two Arrays within a loop
by moritz (Cardinal) on Jun 10, 2013 at 15:45 UTC

    I don't understand your question. First you say I need to remove a specified number of elements from the @_ array at once rather than the one-at-a-time that shift does, which your code does with splice.

    But then you give it the same input as before, and expect the same outcome, even though you changed the code. Why did you even change the code if you don't want it to change? And how do you expect you will ever get more than two elements into @merge_list, when all you do is to create a new variable and assign to elements to it?

      Sorry for not being clear the issue is that the first part of the code is the original code that I have to modify to work using Splice. Since I am a noobie with Perl the bottom code is my attempt which is not working. I need to use splice to make this work as part of my assignment.

        Here is the splice version. Make sure you understand what's going on before you submit to whomever... (there is a twist...)

        #!/usr/bin/perl use strict; use warnings; my @first = qw(Can unlock secret); my @second = qw(you the code?); my @mixed = interleave_words( scalar(@first), @first, @second ); print "Result: @mixed\n"; sub interleave_words { my $count = shift; my @results = splice @_, $count; foreach my $index ( 0 .. $count-1 ) { splice @results, 2*$index, 0, shift; } return @results; }
      Applogies: I have a assignment as follows: "This program can be made both shorter and faster by using a built-in function named splice that will remove a specified number of elements from the @_ array at once, rather than the one-at-a-time that shift does." Using the existing code I need to change it to use splice and have the same exact output. As you can see it is not working. I need some help in this. Thanks

        Be very careful when you ask for "short" code on this website, you might get what you ask for ... ;) like this (meeting your requirement to use splice):

        sub interleave_words { my @results = splice @_, shift; splice @results, 2*$_, 0, shift for 0..@results-1; return @results; }
Re: Using Splice with Two Arrays within a loop
by hdb (Monsignor) on Jun 10, 2013 at 15:54 UTC

    Your function already exists in module List::MoreUtils.

    use strict; use warnings; use List::MoreUtils qw{ mesh }; my @first = qw(Can unlock secret); my @second = qw(you the code?); my @mixed = mesh @first, @second; print "Result: @mixed\n";

    UPDATE: Again a few seconds too late... davido being faster again!