Pathologically Eclectic Rubbish Lister PerlMonks

### match two elements from an array in a row

by cengineer (Pilgrim)
 on Aug 16, 2007 at 21:33 UTC Need Help??

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

I'm looking to find a particular number in an array twice in a row. More specifically, I'm looking to match 81 or 82. Is there a better or more elegant approach than something like:
```
my @data = qw ( 01 b2 01 00 b6 81 81 01 b4 0a 01 01 01 01 00 01 00 00
+01 00 c7 82 82 01 b2 01 00 b8 );

for ( my \$i = 0; \$i < \$#data; \$i++ ) {
if ( \$data[\$i] eq "81" ) {
if ( \$data[\$i+1] eq "81" ) {
print "match 81 starting at index \$i\n";
}
}
elsif ( \$data[\$i] eq "82" ) {
if ( \$data[\$i+1] eq "82" ) {
print "match 82 starting at index \$i\n";
}
}
}

Replies are listed 'Best First'.
Re: match two elements from an array in a row
by dogz007 (Scribe) on Aug 16, 2007 at 22:25 UTC
You could use List::Util and take advantage of reduce:

```use strict;
use List::Util qw(reduce);

my @data = qw ( 01 b2 01 00 b6 81 81 01 b4 0a 01 01 01 01 00
01 00 00 01 00 c7 82 82 01 b2 01 00 b8 );

my \$index;
reduce {  if (\$a eq \$b && \$a =~ m/81|82/) {
print "match \$a starting at index \$index\n"}
\$index++;
\$b;
} @data;

Prints:

```match 81 starting at index 6
match 82 starting at index 22

Update: If you would prefer to use a for loop, you should use the range operator as below. Much cleaner to read. I guess I got carried away with the reduce.

```for my \$i (0 .. \$#data) {
if ( \$data[\$i] eq \$data[\$i+1] && \$data[\$i] =~ m/81|82/) {
print "match \$data[\$i] starting at index \$i\n";
}
}

Perhaps premature optimization, but I'd recommend switching your tests around so that you only look for matches of numbers you care about:-

```if (\$data[\$i] =~ m/^(?:81|82)\$/ && \$data[\$i] eq \$data[\$i+1]) {

(Note the addition of anchors in the regex so you don't accidentally match a pair of, say, 181s.)

And if the number of numbers you're trying to matches is likely to grow or change often, it may be easier using a hash instead of a regex:-

```my %wanted = map { \$_, 1 } qw(
81
82
);

# ...

for my \$i (0 .. (\$#data - 1)) {
if (exists \$wanted{\$data[\$i]} && \$data[\$i] eq \$data[\$i+1]) {

--k.

Re: match two elements from an array in a row
by graff (Chancellor) on Aug 17, 2007 at 03:02 UTC
```my @data = qw( 01 b2 01 00 b6 81 81 01 b4 0a 01 01 01 01
00 01 00 00 01 00 c7 82 82 01 b2 01 00 b8 );

for ( 1 .. \$#data ) {
if ( \$data[\$_] =~ /(8[12])/ and \$data[\$_] eq \$data[\$_-1] ) {
print "Match \$1 ending at index \$_\n";
}
}
(update: rearranged my conditions as perl Kanji's premature optimization. :)
Re: match two elements from an array in a row
by shoness (Friar) on Aug 17, 2007 at 08:53 UTC
Just for fun, I wanted to try this with the regexp engine...
```#!/usr/bin/perl
use strict;
use warnings;

my @data = qw ( 01 b2 01 00 b6 81 81 01 b4 0a 01 01 01 01 00
01 00 00 01 00 c7 82 82 01 b2 01 00 b8 );

\$_ = join(' ', @data);

while ( /(8[[:xdigit:]])\s+\1/g ) {
print "Duplicate \$1 found at character " . pos() . "\n";
}
Produces...
```bash\$ superdoc.pl
Duplicate 81 found at character 20
Duplicate 82 found at character 68
Using...
```# while ( /([[:xdigit:]]{2})\s+\1/g ) {
instead, will match any repeated hex digit...
```bash\$ superdoc.pl
Duplicate 81 found at position 20
Duplicate 01 found at position 35
Duplicate 01 found at position 41
Duplicate 00 found at position 53
Duplicate 82 found at position 68
Cheers!

Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://633177]
Approved by BrowserUk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (3)
As of 2023-11-29 15:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?

No recent polls found

Notices?