2

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;
12
  • 2
    I tend to view gratuitous language comparisons very negatively. So, you do not how to do something in Perl which you do know how to do in PHP. You can simply ask "How can I do X in Perl?" instead of complaining about the syntax of a language whose documentation you don't seem to have read at all. See perldoc.perl.org/perldsc.html Commented Jun 18, 2010 at 20:53
  • 3
    @Ben That is why you need to actually study a language a little bit, understanding the basic rules of it before you accept a job that requires you to use it. Commented Jun 18, 2010 at 21:04
  • 2
    @Ben: you shouldn't need to google anything; the canonical perl documentation has everything you need. perldoc perldsc has non-trivial examples. But as a programmer, you know that complicated tasks are really just a bunch of simple tasks wrapped around each other. Reduce each task to simple atomic items and it all becomes clear. Commented Jun 18, 2010 at 21:10
  • 4
    @Ben Speed of all things should not be a criterion in choosing between Perl and PHP. Since you seem to know PHP and seem to have working code in PHP, I could not think of any other reason than a job requirement for using Perl. If you are doing this as a learning exercise, you should treat this as such and consider getting a book. learn.perl.org/books.html Commented Jun 18, 2010 at 21:19
  • 2
    @Sinan, Ben - BREAK! Boxing match is over :) @Ben - Saying "Perl has some strange syntax to it" as opposed to "Perl has a syntax that I find harder to understand" does sound a bit insulting, even if you didn't mean that. I'd suggest you edit the wording. @Sinan - if you peruse Ben's previous questions it leaves the impression that he is diligently trying to learn and putting some honest effort into it. So please be nicer to a new convert :) Commented Jun 19, 2010 at 1:17

3 Answers 3

4
$indexed{ $r->[0] }{'image_id'} = $r->[0];
Sign up to request clarification or add additional context in comments.

4 Comments

Global symbol "%indexed" requires explicit package name at ./db_index.pl line 79.
"my %indexed;" is enough to define it.
@Ben: you were attempting to use the %indexed symbol in your example, so hobbs naturally assumed that you had already declared it.
@Ether @hobbs Sorry about that. I redeclared that as the %indexed, instead of $indexed.
3

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.

7 Comments

@Sinan I'm using dumper, but I get this result. It's a step forward, but it doesn't look quite right. $VAR1 = 'ARRAY(0x1ce7f88)'; $VAR2 = { 'image_id' => [ 3638584, 'Aperture', 'F13' ], 'ARRAY(0x1ce7f70)' => [ 3638584, 'Exposure Bias', '0 EV' ] };
@Ben: if you're getting that output, you're not using Data::Dumper.
@Ether I think he is interpolating array references. @Ben Did you write $r instead of $r->[0] in $indexed{ $r->[0] }? The example works just the same with Data::Dumper.
@Sinan I added a print into the loop, and it seems to be setting $r to the same value as @$table, which makes no sense at all. I did a print Dumper $r; to verify that.
@Ben - the name of them method implies that it returns an array reference as opposed to an array, thus you'd need $toindex = $sth->fetchall_arrayref; and elsewhere use @$toindex to use the array and $toindex->[$i] to use its elements. This page provides a good example of using DBI in general and fetchall_arrayref() in particular: felixgers.de/teaching/perl/perl_DBI.html
|
3

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}.

1 Comment

Accessing an array reference with @$r[0] is actually accessing a slice of length one. When evaluated in scalar context, this acts like the , operator and returns the last element in the slice. So @$r[0] gets you the same thing as $$r[0], but in a convoluted and weird way. Personally, I'd stick with $r->[0], its easier all around.

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.