in reply to Re^7: Combinations of lists, etc
in thread Combinations of lists to a hash

Thanks for that, LanX,

"Do you need the hashes to different instances with same content?"
If I understand your question correctly, then yes.  See example in update #2 of my original post.  It's a hash of a hash and the inner hashes have the same keys and values (for a given line of input data).

After some more experimenting, since multiplying the right hand side (e.g. with 'x2') is not going to work (the reason for which still isn't clear to me), then what would be wrong with this kind of strategy: Multiply a string first then eval it:

perl -MData::Dump -e '$val="(".("{(a,1),(b,2)},"x2).")";@hash{(key1,ke +y2)} = eval $val;dd $val;dd \%hash' "({(a,1),(b,2)},{(a,1),(b,2)},)" { key1 => { a => 1, b => 2 }, key2 => { a => 1, b => 2 } } # Or more concisely: perl -MData::Dump -e '@hash{(key1,key2)} = eval "(".("{(a,1),(b,2)},"x +2).")";dd \%hash'
At least it seems to do what's required.  I know there's a trailing ',' in $val which could easily be removed, but doesn't seem to be causing a problem with the resulting hash.

Replies are listed 'Best First'.
Re^9: Combinations of lists, etc
by AnomalousMonk (Archbishop) on Oct 07, 2019 at 22:51 UTC

    The only way I can see right now to deal with * vis-a-vis glob is to replace it with a character that occurs nowhere else in your data. So maybe (if tybalt89 hasn't already solved this):

    c:\@Work\Perl\monks\tel2>perl -wMstrict -MData::Dump -le "use constant NEVER_PRESENT => qq{\x01}; ;; my $s = 'Prefix5,Prefix6:A,B:*:1,23 value7=10|value88=123'; ;; $s =~ s{ [*] }{${ \NEVER_PRESENT }}xmsg; ;; my ($keyule, $valule) = split ' ', $s, 2; ;; $keyule =~ s{ : }[}:{]xmsg; $keyule = qq[{$keyule}]; print qq{'$keyule'}; $valule =~ s{ [|] }{,}xmsg; $valule = qq[{$valule}]; print qq{'$valule'}; ;; my %hash; for my $v (glob $valule) { my ($vk, $vv) = split '=', $v; for my $k (glob $keyule) { $k =~ s{ ${ \NEVER_PRESENT } }{*}xmsg; $hash{$k}{$vk} = $vv; } } dd \%hash; " '{Prefix5,Prefix6}:{A,B}:{☺}:{1,23}' '{value7=10,value88=123}' { "Prefix5:A:*:1" => { value7 => 10, value88 => 123 }, "Prefix5:A:*:23" => { value7 => 10, value88 => 123 }, "Prefix5:B:*:1" => { value7 => 10, value88 => 123 }, "Prefix5:B:*:23" => { value7 => 10, value88 => 123 }, "Prefix6:A:*:1" => { value7 => 10, value88 => 123 }, "Prefix6:A:*:23" => { value7 => 10, value88 => 123 }, "Prefix6:B:*:1" => { value7 => 10, value88 => 123 }, "Prefix6:B:*:23" => { value7 => 10, value88 => 123 }, }
    Ok, now what's the next phase in the dance-of-the-seven-veils requirement disclosure?

    Update: BTW: I'm still not convinced that glob is the way to go with this application. An algorithmic permuter (update: such as haukex describes) or parser would be more to my liking, but it's your project.


    Give a man a fish:  <%-{-{-{-<

      Nice work, AnomalousMonk.  Thanks for that.

      Why would you prefer replacing the '*' (and reverting it after the 'glob'), over escaping it (which requires no reverting afterwards), e.g.:
      $s =~ s/\*/\\$&/g;

        Because I couldn't get it to work. :)

        Update: I thought I had that working, but it doesn't seem to work now, and I don't have time ATM to mess with it.


        Give a man a fish:  <%-{-{-{-<

Re^9: Combinations of lists, etc
by LanX (Saint) on Oct 07, 2019 at 21:55 UTC
    > If I understand your question correctly, then yes.

    I'm afraid you don't.

    The old approach is fine as long as you only read from the data structure without changing it...

    (The fact that the output of Data::Dump is confusing you doesn't mean it doesn't "work".)

    DB<82> $hash{$_} = $value for @keys; DB<83> x \%hash 0 HASH(0x3598330) 'Prefix1=A:b:1' => HASH(0x35a48e8) 'a' => 1 'b' => 2 'Prefix1=A:b:2' => HASH(0x35a48e8) -> REUSED_ADDRESS 'Prefix1=A:c:1' => HASH(0x35a48e8) -> REUSED_ADDRESS 'Prefix1=A:c:2' => HASH(0x35a48e8) -> REUSED_ADDRESS DB<84> p $hash{'Prefix1=A:b:1'}{a} 1 DB<85> p $hash{'Prefix1=A:b:1'}{b} 2 DB<86> p $hash{'Prefix1=A:c:2'}{b} # reading works! 2 DB<87>

    but once you try to add more data it'll be mirrored, because all values of the outer hash point to the same inner hash.

    (Like a symlinked directory if this helps)

    DB<87> p $hash{'Prefix1=A:c:2'}{X}=42 # new entry 42 DB<88> x \%hash 0 HASH(0x3598330) 'Prefix1=A:b:1' => HASH(0x35a48e8) # appears everywhere 'X' => 42 'a' => 1 'b' => 2 'Prefix1=A:b:2' => HASH(0x35a48e8) -> REUSED_ADDRESS 'Prefix1=A:c:1' => HASH(0x35a48e8) -> REUSED_ADDRESS 'Prefix1=A:c:2' => HASH(0x35a48e8) -> REUSED_ADDRESS DB<89>

    So in case you want to store more data inside the inner hashes, which are supposed to be different, you have to clone the hashes.

    > what would be wrong with this kind of strategy:

    Sorry, I don't have even time to discuss all the traps here.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      Thanks again, LanX.

      "The old approach is fine as long as you only read from the data structure without changing it..."

      OK, good.  I'll just be reading it, so I guess it will work for me.  

      I've just ran this which confirms it should work for me:

      perl -MData::Dump -e '@hash{(key1,key2)} = ({a=>1, b=>2}) x 2;dd \%has +h;print "hash{key1}{a}=$hash{key1}{a}\nhash{key1}{b}=$hash{key1}{b}\n +hash{key2}{a}=$hash{key2}{a}\nhash{key2}{b}=$hash{key2}{b}\n"' do { my $a = { key1 => { a => 1, b => 2 }, key2 => 'fix' }; $a->{key2} = $a->{key1}; $a; } hash{key1}{a}=1 hash{key1}{b}=2 hash{key2}{a}=1 hash{key2}{b}=2
      Thanks again for all your help.