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

I'm missing something really stupid here, I know... but I'm asking anyway ;)
$foo = "a c e g i k m o q s u w y"; @bar = split(/ /, $foo); $i = -1; foreach $foo(@bar) { $i++; delete @bar[$i] unless $i eq 2 || $i eq 4 || $i eq 6; } push(@bar,t);
The above will take every second letter of the alphabet, and spit out everything but "i" "m" and "e", and throwing in "t", so that when run, it gives a printout of "eimt". How would I sort this to give "time" instead? I tried messing with split/join, but when I throw in a scalar, I tend to get a numeric character instead.

Replies are listed 'Best First'.
(jeffa) Re: Simple array sorting
by jeffa (Bishop) on Jan 09, 2003 at 05:55 UTC
    @bar[$i] has got to be a mistake, i would say try $bar[$i] instead, but that is wrong as well. delete is for hashes, not arrays. Have you tried looking at what @bar really contains via Data::Dumper?:
    $VAR1 = [ undef, ${\$VAR1->[0]}, 'e', ${\$VAR1->[0]}, 'i', ${\$VAR1->[0]}, 'm', 't' ];
    Not what you thought, huh? Now, if i wanted to create an array that contained every second letter of the alphabet, i would try something like this:
    my $i = 1; my @bar = grep $i++ % 2, ('a'..'z');
    Next, delete all elements but the second, fourth, and sixth:
    @bar = @bar[2,4,6];
    You could combine the two steps:
    my $i = 1; my @bar = (grep $i++ % 2, ('a'..'z'))[2,4,6];
    Finally, push 't' and "@bar" will evaluate to "e i m t". If we could just swap the 't' and the 'e' ...
    ($bar[0],$bar[-1]) = ($bar[-1],$bar[0]);
    Is this what you wanted? Note that this line by itself will not yield the same results if you simply try to cut and paste into your script. Here is my complete script, for convenience:
    use strict; use warnings; my $i = 1; my @bar = (grep $i++ % 2, ('a'..'z'))[2,4,6]; push(@bar,'t'); ($bar[0],$bar[-1]) = ($bar[-1],$bar[0]); print "@bar\n";

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      delete is for hashes, not arrays

      Picking nits ... from perldoc -f delete:

      delete EXPR Given an expression that specifies a hash element, array element, hash slice, or array slice, deletes the specified element(s) from the hash or array. In the case of an array, if the array elements happen to be at the end, the size of the array will shrink to the highest element that tests true for exists() (or 0 if no such element exists).

      -- Hofmator

Re: Simple array sorting
by blokhead (Monsignor) on Jan 09, 2003 at 05:56 UTC
    A few things:

    1: delete @bar[$i] is not quite good coding practice, although it does compile and do what you mean. If you were using warnings, you would have seen the message "Scalar value @bar[$i] better written as $bar[$i]." The code is generally easier to understand when you use the suggested syntax for deleting a single element from array (or usually a hash).

    2: It sounds like you want @bar to be equivalent to be ('t','i','m','e') at the end of the loop. In that case, you don't want to use delete to get rid of them. This removes them from the array, but doesn't shift the remaining elements over to fill the spot. You probably want to use splice instead.

    my @x = qw/a b c d e f g/; delete $x[3]; print join(':', @x), "\n"; # prints a:b:c::e:f:g <-- note the space between c and e @x = qw/a b c d e f g/; splice @x, 3, 1; print join(':', @x), "\n"; # prints a:b:c:e:f:g
    As for getting them in the order you want, I'm a little confused as to why (see below)..

    3: Your foreach $foo(@bar) loop never uses the value of $foo. Maybe a foreach $i (0 .. $#bar) would be better suited for the stuff inside the loop.

    Without knowing exactly what this code is trying to do, it's hard to help. You want to take a sorted list of characters and do something to them (take chars out, add chars in) so that you get a word, which is nothing close to the original list of characters? What is the real-world significance, if any, of the letters you've chosen?

    I'm sorry I can't give any more specific help on your problem, but I'm not sure how (or why) one would sort the letters t,i,m, and e into that order! ;) Let us know what you're heading with this code, and we'll be happy to help more.

    blokhead

      5 min after posting this, I got it =)

      Basically I'm putting up a series of programs for people to go through, find a serious error, fix it, then run it to get a hidden letter.

      The only 'real-world significance' of this, would be for debugging purposes, without taking a shortcut in easily reading the code (unless you spent the time, but faster to fix and run).

      Thanks aswell -- did this in a rush, so I didn't put in a few of those things you pointed out ($bar$i instead of @...). Thanks again.
Re: Simple array sorting
by djantzen (Priest) on Jan 09, 2003 at 06:09 UTC

    The problematic things that strike me are:

    1. It looks like you aren't using strict
    2. Ditto for warnings I bet
    3. Reusing $foo
    4. Using a foreach with a counter, which indicates this ought to be normal for loop
    5. Setting your counter to -1 and then incrementing the counter as the first thing in the loop, effectively starting at zero.
    6. If you know the indexes at which the letters exist that you want, why not simply copy those into a new array?
    7. How do you determine what you want to spell with the letters pulled from the array? How is this supposed to know how to arrange the letters?

    What are you actually trying to accomplish FireBird34?

      The only purpose of this code is for the learning ability, in patching up a syntax error, and getting a code letter out of it (from a series of programs, a certain code will be found for something else). This program (I patched the error so no one will point it out ;)) will generate the letter "u".

      Now I know there is alot of useless garbage in the program, but that is the point -- I don't want the person to just look at a statement like 'print "u";', but throw something in there to make it look 'bigger' than it actually is... and yes, I know there is a commented line reguarding a random call -- that was on purpose.

      Anyway, as I said, this is for the purpose of finding an error in a piece of code, fixing it, and running it to obtain something. Here is the final result that is being used:
      #!/usr/bin/perl use strict; use warnings; my @a = 'a'..'z'; my $b = $a[19]; &blah(); srand('5' ^ my $blah1); my @c=split(/ */, "abcdefghijklmnopqrstuvwxyz"); my $a = $c[20]; for(my $i = 0) { @c = $c[20];#!/\^s/[int(rand(20))]/\^s/; print "Good job!\n\nCode Letter: @c"; } sub blah { my $blah = "a c e g i k m o q s u w y"; my @blah = split(/ /, $blah); my $i = -1; foreach $blah(@blah) { $i++; delete $blah[$i] unless $i eq 2 || $i eq 4 || $i eq 6; } $blah = join('', $b,$blah[4],$blah[6],$blah[2]); @blah = $blah; $blah1 = @blah; }

        Who is supposed to learn from this exercise? What are they supposed to learn? You've got a bitwise XOR seeding srand, rand, regular expressions, and the infrequently used int. At the same time, the surrounding code is blatantly obtuse: my declarations in the operations that use them, a braindead for loop, an even worse foreach, reuse of variable names. I mean, you've got high-level constructs surrounded by horrifically poor code. If this test is intended for someone relatively new to Perl, there is no way they are going to find some minor error in your code, because they're going to be too busy wondering what ^ means and what the difference is between / / and / */! On the other hand, if you're looking at a mid- to upper-midlevel Perl coder who actually knows what those things do, you're wasting their time having them wade through garbage that they ought to be smart enough not to write in the first place.

        Seriously, if you want someone to learn Perl, focus on proper use of the language, such as making smart choices regarding control statements and data types given certain needs. Save the tricks for entertainment purposes, because all the learner is going to get out of it is a feeling of bewilderment, but that is not the point of instruction.

Re: Simple array sorting
by Zaxo (Archbishop) on Jan 09, 2003 at 05:58 UTC

    I'd write @bar and extract elements indexed 2,4,6 like this:

    my @bar = qw(a c e g i k m o q s u w y); @bar = @bar[2,4,6]; push @bar, 't';
    but I have no idea why you want to do this.

    If you want to verify that you can anagram to 'time' with some permutation, just do print "True\n" if 'eimt' eq join '', sort @bar; If your problem is more general, please explain what it is.

    After Compline,
    Zaxo