Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

grepping the location of a value from a datastructure

by rastoboy (Monk)
on Aug 07, 2013 at 16:02 UTC ( [id://1048372]=perlquestion: print w/replies, xml ) Need Help??

rastoboy has asked for the wisdom of the Perl Monks concerning the following question:

Greetings Brothers,

I'm not even sure how to phrase this question. I want to get the *location* of a value in a datastructure, as opposed to just seeing if it's there or not.

For example:

#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my $hash = { base => { key => 'value', key2 => 'value2'}}; print Dumper $hash; my @output = grep $hash, 'value2'; print "@output\n";
will output:
rasto@sauron:~$ ./test.pl $VAR1 = { 'base' => { 'key2' => 'value2', 'key' => 'value' } }; value2
But what I really want is like the location of $VAR1=>{'base'}{'key2'}. How can I get that (elegantly)?

Any help would be greatly appreciated!

rasto

Replies are listed 'Best First'.
Re: grepping the location of a value from a datastructure
by rjt (Curate) on Aug 07, 2013 at 16:47 UTC

    If you want to trundle through an arbitrarily deep reference tree with grep-like syntax, it's actually fairly easy to implement:

    use 5.016; # For __SUB__, or pre-declare $grep and use $grep->() s +yntax sub ref_grep(&$) { my ($wanted, $ref) = @_; my $seen = {}; # Refs we've already seen (avoid circular refs) my @found; # Result list my $grep = sub { my ($ref, $path) = @_; return if ref $ref and $seen->{$ref}++; { $_ = $ref; push @found, $path if $wanted->() } for (ref $ref) { when ('HASH') { __SUB__->($ref->{$_}, $path."->{$_}") for sort key +s $ref; } when ('ARRAY') { __SUB__->($ref->[$_], $path."->[$_]") for sort key +s $ref; } } }; $grep->($ref, ''); return @found; }

    Invocation is just like grep:

        say "Found value2: \$hash$_" for ref_grep { $_ eq 'value2' } $hash;

    It's not limited to scalars, either; the BLOCK can perform any test it likes.

    Of course, this is not without limitations. Support for nested objects, tests based on the path itself, pruning, etc., would take more work, and I'd certainly not try much harder to re-invent this wheel. What I'm saying is, take this as a starting point.

    use strict; use warnings; omitted for brevity.
      Thanks for that! I was kinda stuck on grep, and grep needing a list as an argument, but I certainly get the idea.
Re: grepping the location of a value from a datastructure
by Anonymous Monk on Aug 07, 2013 at 16:30 UTC
Re: grepping the location of a value from a datastructure
by RichardK (Parson) on Aug 07, 2013 at 16:37 UTC

    I wonder if this is an XY Problem?

    Can you explain what you are going to do with this *location* once you've got it?

      That's a fair point. I'm doing a text search through a book. I've parsed the book into chapters and paragraph numbers, so that when I find the location I can say "text found at paragraph 10 in chapter 2".

        Then you should probably invert your data structure. Instead of

        my $hash = { base => { key => 'value', key2 => 'value2'}};

        consider

        my $hash = { "value" => [ { 'chapter' => 2, 'paragraph' => 10 }, { 'chapter' => 2, 'paragraph' => 11 }, ... ], "value2" => [ { 'chapter' => 3, 'paragraph' => 1 } ] };
        -derby

        I agree with derby. Your data structure should explicitly model the whole book, including the text, the chapter numbers, and the paragraph numbers. It's better not to infer chapter numbers and paragraph numbers implicitly from their positions within a Perl nested data structure. A well-designed data structure will be extensible. If you decide later you want to model another attribute of the book—say, sentence numbers—you can do so without having to re-implement the data structure or create a new one. The data structure will then also map neatly to an external, reusable representation such as XML.

Re: grepping the location of a value from a datastructure
by Laurent_R (Canon) on Aug 07, 2013 at 17:10 UTC

    But what I really want is like the location of $VAR1=>{'base'}{'key2'}. How can I get that (elegantly)?

    That really does not make much sense to me. Location? With your data, you could presumably say that the location of 'value2' is $hash{'base'}{'key2'}, because 'value2' is stored there. But the location %VAR1 being {'base'}{'key2'}, this I don't understand.

      Sorry, like I said I wasn't even sure how to phrase the question. The first thing you said is what I'm after.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1048372]
Approved by toolic
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (1)
As of 2024-04-18 23:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found