4

I have written a script which passes a scalar and hash data into an subroutine.

While passing an hash I was passing an reference and inside the subroutine dereferencing it while iterating (using foreach loop).

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

my %hash = (
                '1' => [ 'A', 'B', 'Z', 'A' ],
                '2' => [ 'C', 'D' ],
                '3' => [ 'E', 'E' ]
);

my $keyword = "my_test_keyword";
print_data($keyword, \%hash);
print "End of the Program\n";

sub uniq (@) {
    my %seen;
    my $undef;
    my @uniq = grep defined($_) ? !$seen{$_}++ : !$undef++, @_;
    @uniq;
}

sub print_data {
    my ($kw, $h) = @_;
    print "Keyword:$kw\n"; #my_test_keyword should be printed
    
    foreach my $key (sort keys %$h) {
        print "Key:$key\n";
        print "Value(s):", join('#', uniq @{%$h{$key}}), "\n";
    }
    return;
}

Is it a good approach or do I need to pass hash as it is (without reference) and retrieve in subroutine.

TLP
  • 66,756
  • 10
  • 92
  • 149
vkk05
  • 3,137
  • 11
  • 25
  • 4
    1. Nothing wrong with hashref (can only be preferred) 2. There is `List::Util::uniq`, in core (or `List::MoreUtils::uniq` in older versions) 3. Do you really need prototypes? 4. Try before posting: that `%$h{$key}` under `@{}` is wrong, need `$h->{$key}` – zdim Mar 26 '21 at 07:26
  • @zdim: thanks for the suggestions. I have dependencies issue for `List::Util::uniq`. See [this](https://stackoverflow.com/questions/66776916/get-unique-elements-from-hoa-values-and-print) post. Point 4 is noted. – vkk05 Mar 26 '21 at 07:32
  • Ah, OK. The `uniq` used to be in `List::MoreUtils` -- can you install that? (Nothing wrong with using your own, of course) – zdim Mar 26 '21 at 07:33
  • @zdim: Not possible :| thats why I opted out for having `uniq` subroutine in my code itself. – vkk05 Mar 26 '21 at 07:38
  • I like your `uniq` implementation. Although I wouldn't name it uniq since that's so commonly associated with the one in the much used List::Util or List::MoreUtils modules. Also, whats the purpose of collecting the returned array into `@uniq` when you could just let the `grep...` be the last line. Maybe perl optimizes than away, I don't know, otherwise it would use extra cpu cycles and memory without purpose. – Kjetil S. Mar 26 '21 at 11:09
  • Aside from the particular task, that's pretty much what I do. I pass references all over the place. What's bothering you about doing that? – brian d foy Mar 26 '21 at 14:24
  • @briandfoy: Actually I have a huge set of data in my `hash` (it has almost 0.1 million `keys` when I print key count). So thinking with respect to script performance, it would be fine? – vkk05 Mar 26 '21 at 15:12
  • "_Actually I have a huge set of data_" -- then there's no question, you want that passed by reference. Performance effects of that can only be seen when this is used a _lot_, but it probably (generally?) only helps going by reference... – zdim Mar 26 '21 at 18:54
  • ... When passing by reference only that one scalar is copied (while with hash it'd be a list of all keys and values), and a hash need not be constructed in the sub. On the other hand, every time that hashref is used in the sub it need be dereferenced, while when the flat list (hash) is passed those values are on hand in the sub (once a hash is created). So it's a matter of what is done more, the function call or hash manipulations inside, and how much the hash is accessed. Time both versions if it may matter – zdim Mar 26 '21 at 18:57

1 Answers1

2

You can't pass hashes (or arrays) to subs, only zero or more scalars. Using

f(%hash)

results in

f($key1, $hash{$key1}, $key2, $hash{$key2}, ...)

So you would have to recreate the hash on the inside. Passing a reference is a common and much cheaper alternative.

ikegami
  • 367,544
  • 15
  • 269
  • 518