views:

165

answers:

4

I'm just trying to shorten a line of code that assigns HTML::Element->as_trimmed_text from an array of HTML::Elements to some variables - pretty standard stuff like:

my ($var1, var2) = ($columns[1]->as_trimmed_text, $columns[2]->as_trimmed_text);

..except that there's a few more columns so it continues on over a few more lines. I had the bright idea that I could use map instead but I'm not really having much luck. I've tried variations on

map { $_->as_trimmed_text } @columns[1, 3, 5, 7, 9]

but I keep getting Can't call method "as_trimmed_text" without a package or object reference.

Is it possible to do what I'm trying or should I just stick to what I currently have?

TIA

EDIT: column -> columns

+5  A: 

Your map looks right to me. Are you sure the second one should say @columns instead of @column? Do you have strict turned on to catch typos in variable names?

friedo
Metaphysical +1 because I'm still out of upvotes. Curses!
Chris Lutz
`use strict` rocks
Ivan Nevostruev
what's a 'strict rock' ?
pavium
Sorry, typed the code just to give s short example. Yes I use strict and warnings always.
Sparkles
@pavium: "`use strict;`" is good practice
Ivan Nevostruev
@pavium Note the difference between `use strict` rocks vs use strict rocks.
Sinan Ünür
+1  A: 

First and foremost, if you're not interested in the output of map, you shouldn't use map. Map, like grep, sort, etc is a filter. If you don't want the output, use foreach.

But you are correct, map was designed to solve exactly this kind of problem. This will give the output that you desire, although it does not use array slices.

@trimmed_columns = map { $column[$_]->as_trimmed_text } (1, 3, 5, 7, 9);

Robert P's answer explains better why the original didn't work.

Bob
-1. This answer has nothing but true statements and it has valid code, but it doesn't address the question, which was about using `map` with an **array slice**. It also provides no explanation of what was wrong with the original code.
Rob Kennedy
I suppose you are technically correct. I was more concerned with providing a solution for his problem in the most correct way rather than answering the exact question as posted.Since array slices are treated by perl as immutable lists, modifying it inline using map (which you shouldn't do anyway) would be the wrong approach to the problem.I shall modify my answer to be more expressive.
Bob
The code in the problem doesn't modify anything, and there's nothing at all wrong with its use of an array slice...
hobbs
+1  A: 

You're using another variable in second example @columns, but not @column. Try to use following code:

map { $_->as_trimmed_text } @column[1, 3, 5, 7, 9]
Ivan Nevostruev
+8  A: 

Found it:

Here's a bit of code that emulates what should happen:

use strict;
use warnings;

package Text;

sub new
{
   my $class = shift;
   my $text = shift;
   return bless { TEXT => $text }, $class;
}

sub as_trimmed_text
{
   my $self = shift;
   my $text = $self->{TEXT};
   $text =~ s/^\s*(.*?)\s*$/$1/;
   return $text;
}

package main;

my @texts = ( Text->new(' foo '), Text->new(' bar '), Text->new(' baz '));

my @trimmed = map { $_->as_trimmed_text() } @texts[1, 2];

print "Trimmed were: ", join(',', map { "'$_'" } @trimmed);

This works, and works fine; I get:

Trimmed were: 'bar','baz'

But if I replace the map with this line:

my @trimmed = map { $_->as_trimmed_text() } @texts[2, 3];

All of a sudden I get this output:

Can't call method "as_trimmed_text" on an undefined value

This is because '3' is outside the range of valid values in @texts, so it autovivifies a new entry, and makes it undef. Then, your map does

undef->as_trimmed_output()

which barfs. I'd check your array slice again, and make sure that you aren't grabbing values outside the actual indexes available, and barring that, verify that you are actually processing HTML::Element members with that map. A quick Data::Dumper::Dumper on the values in @columns will help immensely.

For example, if you then change your array to contain

my @texts = ( Text->new(' foo '), Text->new(' bar '), ' baz ');

and try to run it, I now get your error:

Can't call method "as_trimmed_text" without a package or object reference at map.pl

So, double check to make sure the contents of your array are actually all blessed instances of the class you're trying to call the method of.

Robert P
Late (probably) correct answers like this make me sad that I'm out of upvotes.
Chris Lutz
@Chris: you say that a lot (that you wish you could upvote, etc.). Why not simply come back the next day and upvote?
Telemachus
This is the most likely answer, with the typo hypothesis eliminated :)
hobbs