I searched SO before asking this question, I am completely new to this and have no idea how to handle these errors. By this I mean Perl language.
When I put this
%name->{#id[$#id]} = $temp;
I get the error Using a hash as a reference is deprecated
I tried
$name{#id[$#id]} = $temp
but couldn't get any results back.
Any suggestions?
The correct way to access an element of hash %name is $name{'key'}. The syntax %name->{'key'} was valid in Perl v5.6 but has since been deprecated.
Similarly, to access the last element of array #id you should write $id[$#id] or, more simply, $id[-1].
Your second variation should work fine, and your inability to retrieve the value has an unrelated reason.
Write
$name{$id[-1]} = 'test';
and
print $name{$id[-1]};
will display test correctly
%name->{...}
has always been buggy. It doesn't do what it should do. As such, it now warns when you try to use it. The proper way to index a hash is
$name{...}
as you already believe.
Now, you say
$name{#id[$#id]}
doesn't work, but if so, it's because of an error somewhere else in the code. That code most definitely works
>perl -wE"#id = qw( a b c ); %name = ( a=>3, b=>4, c=>5 ); say $name{#id[$#id]};"
Scalar value #id[$#id] better written as $id[$#id] at -e line 1.
5
As the warning says, though, the proper way to index an array isn't
#id[...]
It's actually
$id[...]
Finally, the easiest way to get the last element of an array is to use index -1. The means your code should be
$name{ $id[-1] }
The popular answer is to just not dereference, but that's not correct. In other words %$hash_ref->{$key} and %$hash_ref{$key} are not interchangeable. The former is required to access a hash reference nested as an element in another hash reference.
For many moons it has been common place to nest hash references. In fact there are several modules that parse data and store it in this kind of data structure. Instantly depreciating the behavior without module updates was not a good thing. At times my data is trapped in a nested hash and the only way to get it is to do something like.
$new_hash_ref = $target_hash_ref->{$key1}
$new_hash_ref2 = $target_hash_ref->{$key2}
$new_hash_ref3 = $target_hash_ref->{$key3}
because I can't
foreach my $i(keys(%$target_hash_ref)) {
foreach(%$target_hash_ref->{$i} {
#do stuff with $_
}
}
anymore.
Yes the above is a little strange, but creating new variables just to avoid accessing a data structure in a certain way is worse. Am I missing something?
If you want one item from an array or hash use $. For a list of items use # and % respectively. Your use of # as a reference returned a list instead of an item which perl may have interpreted as a hash.
This code demonstrates your reference of a hash of arrays.
#!/usr/bin perl -w
my %these = ( 'first'=>101,
'second'=>102,
);
my #those = qw( first second );
print $these{$those[$#those]};
prints '102'
Related
It seems to me that there simply has to be a better way of doing this, but i still haven't found one. And i'm sure i'm not the only one who could use a way to do this: Run an SQL query that only produces one field in one row, then assign that field to a scalar. (In my case, if the query results in more than one field/row, then i have bigger things to worry about than the script breaking).
For example, to get the timestamp from the SQL server, one could use:
my $timestamp;
my $cmd = $dbh->prepare('SELECT cast(now() AS timestamp);') or die $!;
$cmd->execute();
while (my #asd = $cmd->fetchrow_array) { $timestamp = $asd[0] }
Dirty, but it works. But using 4 lines seem a bit much for a simple assignment, especially considering how well perl and postgresql can communicate with eachother via DBI. Sure, i could write a subroutine for it, but isn't there something native that allows me to fetch data as easily as i submit data with $dbh->do() ?
And yes, i did try google.
Usually I write:
$value = $dbh->selectall_arrayref($sql)->[0]->[0];
There's always selectrow_array:
selectrow_array
#row_ary = $dbh->selectrow_array($statement);
#row_ary = $dbh->selectrow_array($statement, \%attr);
#row_ary = $dbh->selectrow_array($statement, \%attr, #bind_values);
This utility method combines prepare, execute and fetchrow_array into a single call.
So something like this:
my $timestamp = $dbh->selectrow_array('select cast(now() as timestamp)');
There's also selectrow_arrayref and selectrow_hashref for similar situations.
From perldoc DBI:
"selectrow_arrayref"
$ary_ref = $dbh->selectrow_arrayref($statement);
$ary_ref = $dbh->selectrow_arrayref($statement, \%attr);
$ary_ref = $dbh->selectrow_arrayref($statement, \%attr, #bind_values);
This utility method combines "prepare", "execute" and
"fetchrow_arrayref" into a single call. It returns the first row of
data from the statement. The $statement parameter can be a previously
prepared statement handle, in which case the "prepare" is skipped.
If any method fails, and "RaiseError" is not set, "selectrow_array"
will return undef.
That will get you most of the way. You still need to do some error checking, but you would be doing that anyway.
Wouldn't fetchrow_array actually only return a scalar as you're only asking for one column?
So I am trying to learn Linked Lists using Perl. I am reading Mastering Algorithms with Perl by Jon Orwant. In the book he explains how to create a linked list.
I understand most of it, but I just simply fail to understand the command/index/key NEXT in the second last line of the code snippet.
$list=undef;
$tail=\$list;
foreach (1..5){
my $node = [undef, $_ * $_];
$$tail = $node;
$tail = \${$node->[NEXT]}; # The NEXT on this line?
}
What is he trying to do there?
Is $node a scalar, which stores the address of the unnamed array? Also even if we are dereferencing $node, should we not refer to the individual elements by an index number, such as (0,1). If we do use NEXT as a key, is $node a reference to a hash?
I am very confused.
Something in plain English will be highly appreciated.
NEXT is a constant, declared earlier in the script. It contains an integer value representing the index of the current node's member element that refers to the next node.
Under this scheme, each node is a small anonymous array. One element of this anonymous array contains the payload, and the other contains a reference pointing to the next node.
If you look at some of the earlier examples in that chapter you will see the following declarations:
use constant NEXT => 0;
use constant VAL => 1;
So $node->[NEXT] is synonymous to $node->[0], which contains a reference to the next node in the linked list chain, while $node->[VAL] is synonymous with $node->[1]; the value (or payload) stored in the current node.
I'll comment on the code snippet you provided:
foreach (1..5){
my $node = [undef, $_ * $_]; # Create a new node as an anon array.
# Set the previous node's "next node reference" to point to this new node.
$$tail = $node;
# Remember a reference to the new node's "next node reference" element.
# So that it can be updated when another new element is added on next iteraton.
$tail = \${$node->[NEXT]}; # The NEXT on this line?
}
Excellent book, by the way. I've got several algorithms books, and that one continues to be among my favorites after all these years.
Update: I do agree that the book isn't a model of current idiomatic Perl, or current "best practices" Perl, but do feel it is a nice resource for gaining an understanding of the application of classic algorithms with Perl. I still refer back to it from time to time.
NEXT is a constant, declared on an earlier page, that contains a number. Its being used instead of just the regular number to access the array ref $node so the reader knows that slot is where the next element in the linked list is stored.
It's a technique to use array references to store things other than lists. The technique was intended to save memory and CPU time compared to using a hash reference. In reality it doesn't make much performance difference and its awkward to work with. The book is quite a bit out of date in its ideas about how to write Perl code. Use a hash reference instead.
my $list;
my $tail = \$list;
foreach my $num (1..5) {
my $node = { data => $num };
$$tail = $node;
$tail = \$node->{next};
}
Like in Perl, if a hash key is uninitialized then if you perform the below code
$hash{$key} =~ $hash{$key}++
then the value for that particular key increases to 1 (cause, it's first undefined and then as per the context, here it's numaical ... it takes the value to 0 ... increases it to 1).
My question is, does the same concept follows in case of C# as well? I mean, if I perform the above code in c# what would be the result? Will it be 1 or what?
Any idea?
Thanks,
Rahul
That bit of code makes no sense.
If you want to know if the key exists in the hash:
if (exists $hash{$key}) { ... }
If you want to know if it has a value defined:
if (defined $hash{$key}) { ... }
If you want to increment the value,
$hash{$key}++
As it is, you're attempting to do a regex match in a rather nonsensical way.
OOPS!!! Sorry ... I got it; actually the Perl code mentioned is meant to check/confirm whether the particular "KEY" exist or not ... OR sort of that.
So, in C# I cna just check for "hashtable.containskey(key)" ... that will do the trick.
Thanks.
I'm working with perl, and using DBI. Up to now, I've been using ->fetchall_arrayref to get the results of a database query, and just accessing the array by numeric keys. However, I much prefer to be able to access records by the field names (associative fetch) than numeric.
How do I do this, and what is the correct syntax for accessing the keys?
I would prefer something like:
$data[0]['name']
Instead of:
$data[0][1]
Working Solution
my %data;
#{$data{$id}}{('name')} = 'something';
Read the DBI docs. Particularly, fetchall_hashref.
And you should also learn Perl syntax, as it's not the same as PHP.
You can use selectall_arrayref for this. Here's example from the DBI manpage:
You may often want to fetch an array of rows where each row is stored as a hash.
That can be done simple using:
my $emps = $dbh->selectall_arrayref(
"SELECT ename FROM emp ORDER BY ename",
{ Slice => {} }
);
foreach my $emp ( #$emps ) {
print "Employee: $emp->{ename}\n";
}
If you do fetchall_hashref() then you get the hash you are looking for. The keys will be the field names from the database. I am a little late, and Joe got it, but it will be.
$data->{0}->{'field'};
It seems to me that some of these should fail, but they all output what they are supposed to:
$, = "\n";
%test = (
"one" => ["one_0", "one_1"],
"two" => ["two_0", "two_1"]
);
print #{$test{"one"}}[0],
#{$test{"one"}}->[0],
$test{"two"}->[0],
$test{"one"}[1];
Why is this?
Your first example is different than the others. It is an array slice -- but in disguise since you are only asking for one item.
#{$test{"one"}}[0];
#{$test{"one"}}[1, 0]; # Another slice example.
Your other examples are alternative ways of de-referencing items within a multi-level data structure. However, the use of an array for de-referencing is deprecated (see perldiag).
#{$test{"one"}}->[0]; # Deprecated. Turn on 'use warnings'.
$test{"two"}->[0]; # Valid.
$test{"one"}[1]; # Valid but easier to type.
Regarding the last example, two subscripts sitting next to each other have an implied -> between them. See, for example, the discussion of the Arrow Rule in perlreftut.