Detecting element types in a mixed array

Im working with some code that has a routine that includes an array reference as one of the parameters. The elements of this incoming array can be either small arrays or strings.

I want to determine what type of each element is needed to do something specific (i.e. if the element is an array, collapse it further by indexing, if this element is a string, use a string)

I tried using the ref function to poll each element of the array. This seems to work for elements that are ARRAY, but if the element is a string, I expected ref return SCALAR. However, ref() does not seem to return anything. What am I doing wrong? I would think that ref() will return something.

Here is a sample code:

 my @array = ("string1", ["ele1_arraystr1", "ele1_arraystr2"], "string2", ["ele4_arraystr1", "ele4_arraystr2"], "etc"); my $tmp; &foobar( 30, 20, \@array); sub foobar { my($var1, $var2, $array_ref) = @_; foreach $element (@$array_ref) { my $tmp = ref($element); print "Array element type: $tmp\n"; if ($tmp eq 'ARRAY') { print " ARRAY: $element->[1]\n"; } elsif ($tmp eq 'SCALAR') { print " SCALAR: $element\n"; } else { print " Unexpected type: $tmp\n"; } } } 

The result looks something like this:

 ARRAY element test: Array element type: Unexpected type: Array element type: ARRAY ARRAY: ele1_arraystr2 Array element type: Unexpected type: Array element type: ARRAY ARRAY: ele4_arraystr2 Array element type: Unexpected type: 
+7
arrays perl ref scalar
source share
2 answers

ref returns an empty string if its argument is not a link. Docs say

Returns a non-empty string if EXPR is a reference, an empty string otherwise. The return value depends on the type of object referenced by the link.

The following list, including SCALAR , are the types to which the link may refer.

So, when it has a string, it returns an empty string, which evaluates to false. If you knew it was ARRAY or a string, you can do

 if (ref($element) eq 'ARRAY') { # process the arrayref } else { # process the string } 

It is better to check the string (false), as you have, so that you can detect any other types

 my $ref_type = ref($element); if ($ref_type eq 'ARRAY') { # process arrayref } elsif (not $ref_type) { # process string } else { print "Got type $ref_type\n" } 
+5
source share

All of this is described in perldoc perlfunc in the ref section.

ref returns false if its parameter is not a reference. It will return SCALAR only if the parameter is a reference to a scalar.

You may also need to know that to refer to blissful data - the Perl object - ref returns the class in which the data was included, and not the underlying data type. If you need to make a distinction between them, then the Scalar::Util module provides blessed , which returns a class that has blessed data and a reftype that returns the type of the underlying data, just like ref

You can do foobar recursion to handle an undefined nested data structure like

 use strict; use warnings 'all'; use feature 'say'; my @array = ( "string1", [ "ele1_arraystr1", "ele1_arraystr2" ], "string2", [ "ele4_arraystr1", "ele4_arraystr2" ], "etc", [ "etc1", "etc2" ] ); foobar(\@array); sub foobar { my ($val, $indent) = (@_); $indent //= 0; my $ref = ref $val; if ( $ref eq 'ARRAY' ) { foobar($_, $indent+1) for @$val; } elsif ( not $ref ) { say ' ' x $indent, $val; } } 

Exit

  string1 ele1_arraystr1 ele1_arraystr2 string2 ele4_arraystr1 ele4_arraystr2 etc etc1 etc2 

Alternatively, if your array always consists of alternating strings and array references, it might be easier for you to simply assign its hash. This would use strings as hash keys with their corresponding array references as hash values.

This code shows the idea. I used Data::Dump to show the resulting data structure

 my %data = @array; use Data::Dump; dd \%data; 

Exit

 { etc => ["etc1", "etc2"], string1 => ["ele1_arraystr1", "ele1_arraystr2"], string2 => ["ele4_arraystr1", "ele4_arraystr2"], } 
+4
source share

All Articles