3

I'm trying to see if keyword_objects has an element {name=>'CRASH', status=>'+'}.

# $bug is a reference to the below data
{ 
 'keyword_objects' => [ 
    bless( { 'name' => 'CRASH', 'status' => '+'}, 'SomeModule::SomeFilename' ), 
    bless( { 'name' => 'CUSTOMER', 'status' => '-' }, 'SomeModule::SomeFilename' ) ],
 'category' => 'error'
}

I couldn't find something like filter in another language so my alternative was using map.

my @isCrash = map { $_->name eq 'CRASH' && $_->status eq '+' } @{ $bug->{keyword_objects} };

The problem with this is that, when there is no such keyword, every time the operation is done, it seems to return an empty value. @isCrash becomes an array of multiple empty values and if(@isCrash) becomes useless. I surely can introduce a new variable which can be changed from the map operation but I feel like there should be a better way to do it. Someone please chime in and share your knowledge.

4
  • 2
    "something like filter" is grep, and it is precisely a filter; it seems that you can just replace map with grep. But I have serious questions here. The elements of the arrayref are objects -- why do you create them on the fly like that? What's the purpose of having objects without any methods etc? Then they can only be queried like mere hashrefs, since there's no other tools in these ad-hoc classes ... but that's just bad practice. Does this stand for some other, more complex code? Commented Nov 20, 2020 at 6:36
  • 1
    [cont'd] ... Also, the $_->name implies that there is a method name ("getter" for that attribute) -- so if there actually exits a class built somewhere then why do you not use its constructor (new) here? Commented Nov 20, 2020 at 6:44
  • 1
    Now if you'd like to clarify (answer my questions from the first comment) we can perhaps put this in a reasonable answer. (Or perhaps you really just want to stick grep there instead of map ... :) Commented Nov 20, 2020 at 6:52
  • @zdim 1. I didn't know grep could be used to filter an array! :) 2. I'm editing a submodule and that was the given argument. When I looked into the package SomeModule::SomeFilename, it has submodules and all that. Thank you a lot! Commented Nov 20, 2020 at 10:02

2 Answers 2

6

In Perl (and, indeed, in Unix in general), filter is spelled grep.

my $is_crash = grep { $_->name eq 'CRASH' and $_->status eq '+' }
                 @{ $bug->{keyword_objects} };

From perldoc -f grep:

grep BLOCK LIST
grep EXPR,LIST

[ ... snip ...]

Evaluates the BLOCK or EXPR for each element of LIST (locally setting $_ to each element) and returns the list value consisting of those elements for which the expression evaluated to true. In scalar context, returns the number of times the expression was true.

So $is_crash will contain the number of elements in your input list where the expression is true. And that can be used as a Boolean value (as zero is false and all other integers are true).

Sign up to request clarification or add additional context in comments.

Comments

3

Your code mapped every entry to scalar value of logical expression (true of false).
Try the code below to map it to entry itself for match and empty list for no match.
Sum of multiple empty lists is empty list.

my @isCrash = map { $_->name eq 'CRASH' && $_->status eq '+' ? ($_) : () } @{ $bug->{keyword_objects} };

Alternative approach is to use grep:

# get list of "crashed" elements 
my @CrashedList = grep { $_->name eq 'CRASH' && $_->status eq '+'} @{ $bug->{keyword_objects} };
# get number of "crashed" elements in scalar context
my $numberOfCrashes = grep { $_->name eq 'CRASH' && $_->status eq '+'} @{ $bug->{keyword_objects} };

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.