0

I have a hash of hashes storing data like so

our %deviceSettings = (
  BB => {
          EUTRA => {
            DL => { CPC => "NORM", PLCI => { CID => 88 }, ULCPc => "NORM" },
            UL => {
                    REFSig  => { DSSHift => 2, GRPHopping => 1, SEQHopping => 1 },
                    SOFFset => 0,
                  },
          },
        },
  ...
);

I can walk the structure and find a particular key, say CID, and retrieve its value and store the 'path' in an array ('BB', 'EUTRA', 'DL', 'PLCI').

I can also explicitly set a value, like this

$deviceSettings_ref->{BB}{EUTRA}{DL}{PLCI}{CID} = 99

But I want to know how to set a value programatically using a discovered path.

Borodin
  • 126,100
  • 9
  • 70
  • 144
JonFitt
  • 303
  • 2
  • 9

2 Answers2

2

You can walk up the hash using a placeholder $hashref:

my $hashref = \%deviceSettings;

$hashref = $hashref->{$_} for qw(BB EUTRA DL PLCI);
$hashref->{CID} = 'My New Path';

use Data::Dump;
dd \%deviceSettings;

Outputs:

{
  BB => {
          EUTRA => {
            DL => { CPC => "NORM", PLCI => { CID => "My New Path" }, ULCPc => "NORM" },
            UL => {
                    REFSig  => { DSSHift => 2, GRPHopping => 1, SEQHopping => 1 },
                    SOFFset => 0,
                  },
          },
        },
}
Miller
  • 34,962
  • 4
  • 39
  • 60
  • Thanks. Walking the hashref down the tree using a for loop (I used an array as input) is just what I needed. If anyone's interested this is what it looks like: My hash walker runs a function when it finds a given key and passes it the key in $k, and a list of the path in @$key_list. For example $k = CID and @$key_list = ['BB', 'EUTRA', 'DL', 'PLCI', 'CID'] ` pop @$key_list; my $hashref = \%deviceSettings; $hashref = $hashref->{$_} for (@$key_list); $hashref->{$k} = 'My New Value'; ` Very straight forward. Many thanks. – JonFitt Apr 01 '14 at 18:38
2

Data::Diver is a module for accessing nested structures using paths.

use Data::Diver 'DiveVal';

my $device_settings_rf = {};
my @path = ( 'BB', 'EUTRA', 'DL', 'PLCI', 'CID' );
DiveVal( $device_settings_rf, \(@path) ) = 99;
ysth
  • 96,171
  • 6
  • 121
  • 214
  • Thanks. That looks like it would do what I needed, but the other answer uses built-in functionality which will be easier to deliver without the Data::Diver package. – JonFitt Apr 01 '14 at 18:44
  • ah, it wasn't clear from your original question that all the keys for any path you want already exist; Data::Diver is probably overkill then. – ysth Apr 01 '14 at 19:23
  • 1
    Should be `DiveVal( $device_settings_rf, map \$_, @path )` if any elements of `@path` could be a number – ikegami Apr 04 '21 at 18:06