Ben Dauphinee
Ben Dauphinee

Reputation: 4181

Looping over an array to build a multidimensional array in Perl, converting from PHP, and syntactically wrong

Working on converting an array to another array. In PHP, this is easy, but Perl has some syntax that I am having a hard time getting my head around and understanding.

Here is my loop in Perl:

foreach my $r (@toindex){
    #print Dumper $r;
    %indexed{@$r[0]}{'image_id'} = @$r[0];     #Broken
    %indexed{"@$r[0]"}{'image_id'} = @$r[0];   #Broken
}

Here is my @toindex array

$VAR1 = [
      [
        3638584,
        'Aperture',
        'F13'
      ],
      [
        3638588,
        'Exposure Bias',
        '0 EV'
      ],
      [
        3638588,
        'Focal Length',
        '80.0 mm'
      ],
    ];

And here is what I want to do, but in PHP

foreach($indexrows as $k => $v){
    $indexed[$v['image_id']]['image_id'] = $v['image_id'];     
}

It seems so very simple in PHP, but moving it to Perl is proving to be quite a challenge for me.


Update

Thanks to the help of Sinan Ünür and DVK with that final little pointer, I have a working solution. I'm posting the complete script in case anyone might find some part of it useful in the future.

#!/usr/bin/perl
use strict; use warnings; use DBI; use Data::Dumper;

my $dbh = DBI->connect('dbi:Pg:dbname=database;host=serveraddress','user','password') or die;
my $sth;
my $sql = "SELECT id, field, data FROM table";

my $offset = 0; 
my $increment = 20;
my $toindex;

# This loop here is to solve a problem that was not part of the
# original question. I included it to illustrate the syntax for
# looping a database query
do{
    $sth = $dbh->prepare($sql . " LIMIT " . $increment . " OFFSET " . $offset);
    $sth->execute or die;
    $toindex = $sth->fetchall_arrayref;
    $offset = $offset + $increment;
}while(@$toindex == 0);

# Alternately, if you do not need a loop below is all you need
# $sth = $dbh->prepare($sql);
# $sth->execute or die;
# $toindex = $sth->fetchall_arrayref;

my %indexed;
foreach my $r ( @$toindex ) {
    #print Dumper $r;
    my ($id, $field, $value) = @$r;
    @{ $indexed{ $id } }{('image_id', $field)} = ($id, $value);
}

print Dumper %indexed; 

$dbh->disconnect;

Upvotes: 2

Views: 331

Answers (3)

Sinan Ünür
Sinan Ünür

Reputation: 118128

I am going to speculate that you are trying to convert that information to a hash table indexed by the image identifier:

#!/usr/bin/perl

use strict; use warnings;

my $table = [
      [ 3638584 => 'Aperture',      'F13'     ],
      [ 3638588 => 'Exposure Bias', '0 EV'    ],
      [ 3638588 => 'Focal Length',  '80.0 mm' ],
];

my %indexed;

for my $r ( @$table ) {
    @{ $indexed{ $r->[0] } }{('image_id', $r->[1])} = @$r[0,2];
}

use YAML;
print Dump \%indexed;

Output:

E:\Home> t
---
3638584:
  Aperture: F13
  image_id: 3638584
3638588:
  Exposure Bias: 0 EV
  Focal Length: 80.0 mm
  image_id: 3638588

You can write the for loop above less cryptically as:

for my $r ( @$table ) {
    my ($id, $field, $value) = @$r;
    @{ $indexed{ $id } }{('image_id', $field)} = ($id, $value);
}

which might save a lot of headaches a week from now.

See also the Perl Data Structures Cookbook. Perl comes with excellent documentation; use it.

Upvotes: 3

Sinan Ünür
Sinan Ünür

Reputation: 118128

This does not directly answer the question, but it is useful for learning purposes so I am making it CW.

 foreach my $r (@toindex){
     #print Dumper $r;
     %indexed{@$r[0]}{'image_id'} = @$r[0];     #Broken
     %indexed{"@$r[0]"}{'image_id'} = @$r[0];   #Broken
 }
  1. In Perl 5 and earlier, you address an individual element of a hash %hash using the syntax $hash{key} because the element is a scalar.

  2. Hash keys are always stringified. So, used as key to a hash, @$r[0] and "@$r[0]" are identical.

  3. Given a reference to an array $r, there are two ways of accessing its first element. @$r[0] is not wrong, but adding sigils to the front gets tedious after a while. Therefore, I found $r->[0] preferable especially if $r->[0] contains a reference to a nested data structure (not the case here) so I can write $r->[0]{this}[1]{that}.

Upvotes: 3

hobbs
hobbs

Reputation: 239930

$indexed{ $r->[0] }{'image_id'} = $r->[0];

Upvotes: 4

Related Questions