Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

How to Map a scalar to a key that is an array?

by symgryph (Sexton)
on Jul 31, 2019 at 21:28 UTC ( [id://11103671]=perlquestion: print w/replies, xml ) Need Help??

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

I have some data that looks like this:
arn:aws:iam::11111111111:role/ADFS-MyRoleName "Alexa for Business" "AWS Certificate Manager" "AWS Certificate Manager Private Certificate Authority" "AWS Amplify" "Manage - Amazon API Gateway" "AWS App Mesh" "Amazon AppStream 2.0" "AWS AppSync" "Amazon Athena" "AWS Auto Scaling" arn:aws:iam::12345678901:role/Role2-Role2 "Alexa for Business" "AWS Certificate Manager" "AWS Certificate Manager Private Certificate Authority" "AWS Amplify" "Manage - Amazon API Gateway" "Application Auto Scaling" "AWS App Mesh" "Amazon AppStream 2.0" "AWS AppSync"

I would like to create a hashmap so I can count the # of items under each of the 'arn' so the key would be arn:aws:iam::11111111111:role/ADFS-MyRoleName and the values would be everything until the 'blank line' which is the end of record marker. I had thought of using split, but am unsure on how to get the 1:many relationship going. I suspect I need to somehow use a for loop and iterate through each 'arn' value, see what happens between them, and then create a map from that. The only problem is I have no idea how to do this. I looked at data:dumper but this always assumes 1:1 relationships afaik. I couldn't grok it. Could anyone suggest a code snippet that will at least create the datastructure? I can do the rest, but I really am not good at datastructures.

"Two Wheels good, Four wheels bad."

Replies are listed 'Best First'.
Re: How to Map a scalar to a key that is an array?
by haukex (Archbishop) on Jul 31, 2019 at 22:01 UTC

    You probably want to take a look at "Hashes of Arrays" in perldsc, and perhaps perlreftut. There are several ways to process the file, depending on what the largest file is that you want to process, and how large each section can be - for example, you could read the entire file into memory and process that, you could read the file line-by-line and keep the current state in variables, or, the approach that I'll show an example of would be to use the $/ variable to read the file in "paragraph mode", where Perl will break the file apart when it encounters one or more empty lines. Of course, this assumes the file format will always be exactly as you showed it - if there are ever sections that don't conform to the "the first line is the key" pattern, then most likely a slightly more complex approach will become necessary.

    use warnings; use strict; use Data::Dumper; local $/ = ""; # "paragraph mode" my %records; while (<DATA>) { chomp; my @rows = split /\n/; # break apart lines my $key = shift @rows; # first line is hash key $records{$key} = \@rows; # store reference to array in hash } print Dumper(\%records); __DATA__ arn:aws:iam::11111111111:role/ADFS-MyRoleName "Alexa for Business" "AWS Certificate Manager" "AWS Certificate Manager Private Certificate Authority" "AWS Amplify" "Manage - Amazon API Gateway" "AWS App Mesh" "Amazon AppStream 2.0" "AWS AppSync" "Amazon Athena" "AWS Auto Scaling" arn:aws:iam::12345678901:role/Role2-Role2 "Alexa for Business" "AWS Certificate Manager" "AWS Certificate Manager Private Certificate Authority" "AWS Amplify" "Manage - Amazon API Gateway" "Application Auto Scaling" "AWS App Mesh" "Amazon AppStream 2.0" "AWS AppSync"

    Output:

    $VAR1 = { 'arn:aws:iam::11111111111:role/ADFS-MyRoleName' => [ '"Alexa for Business"', '"AWS Certificate Manager"', '"AWS Certificate Manager Private Certificate Authority"', '"AWS Amplify"', '"Manage - Amazon API Gateway"', '"AWS App Mesh"', '"Amazon AppStream 2.0"', '"AWS AppSync"', '"Amazon Athena"', '"AWS Auto Scaling"' ], 'arn:aws:iam::12345678901:role/Role2-Role2' => [ '"Alexa for Business"', '"AWS Certificate Manager"', '"AWS Certificate Manager Private Certificate Authority"', '"AWS Amplify"', '"Manage - Amazon API Gateway"', '"Application Auto Scaling"', '"AWS App Mesh"', '"Amazon AppStream 2.0"', '"AWS AppSync"' ] };
Re: How to Map a scalar to a key that is an array?
by Cristoforo (Curate) on Jul 31, 2019 at 22:04 UTC
    This could be entered into a hash fairly simply. First set the filehandle to read in paragraph mode, (local $/ = ''), within a limited scope (determined by the enclosing braces, {  }). Then a simple split /\n/ will capture the key and the values in an array.

    EDIT: added for loop that removes quotes from beginning and end of items in @data

    Usage: perl my_program.pl input_file

    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %data; { local $/ = ''; while (<>) { my ($key, @data) = split /\n/; for (@data) { s/^"//; s/"$//; } $data{$key} = \@data; } } $Data::Dumper::Indent=1; print Dumper \%data;
    Prints:
    $VAR1 = { 'arn:aws:iam::12345678901:role/Role2-Role2' => [ 'Alexa for Business', 'AWS Certificate Manager', 'AWS Certificate Manager Private Certificate Authority', 'AWS Amplify', 'Manage - Amazon API Gateway', 'Application Auto Scaling', 'AWS App Mesh', 'Amazon AppStream 2.0', 'AWS AppSync' ], 'arn:aws:iam::11111111111:role/ADFS-MyRoleName' => [ 'Alexa for Business', 'AWS Certificate Manager', 'AWS Certificate Manager Private Certificate Authority', 'AWS Amplify', 'Manage - Amazon API Gateway', 'AWS App Mesh', 'Amazon AppStream 2.0', 'AWS AppSync', 'Amazon Athena', 'AWS Auto Scaling' ] };
    (The output is a little messy due to the long key names.)

    EDIT: Used Indent to Data::Dumper to clean up output from Dumper as noted by jdporter

      The output is a little messy due to the long key names

      Please use $Data::Dumper::Indent = 1;

Re: How to Map a scalar to a key that is an array?
by 1nickt (Canon) on Aug 02, 2019 at 13:44 UTC

    If what you want is actually what you say you want ("so I can count the # of items"), please see my solution here (linked as it's four levels deep).


    The way forward always starts with a minimal test.
Re: How to Map a scalar to a key that is an array?
by Anonymous Monk on Jul 31, 2019 at 22:47 UTC
    This is a classic "XY Problem." (Google It.™) You have a problem. But you've already decided now that you need to solve that problem by "Map," which of course requires a "key" which of course can't be "an array" until you (the rabbit-hole journey begins here ...) "concoct a way to do that," etc. The problem being that "the rabbit-hole problem" now becomes the focus of your attention instead of your original problem. "Therefore, STEP BACK!" "THERE'S MORE THAN ONE WAY TO DO IT!™"
      Google it.

      Or you could even search for it here: XY Problem

      I reckon we are the only monastery ever to have a dungeon stuffed with 16,000 zombies.
        I did. Its an interesting read. As a FYI for anyone else having this question, my final program looked Thus:
        #!/usr/bin/perl #use strict; #use warnings; #use Data::Dumper; my %data; { local $/ = ''; while (<>) { chomp; my ($key, $data) = split /\n/; $data{$key} = $data; } } #print %data; my $key; # my $data; foreach $key (keys %data) { # print "$key\n"; print "$key,$data{$key}\n"; }
        "Two Wheels good, Four wheels bad."

      Caveat lector. See also.

      «The Crux of the Biscuit is the Apostrophe»

      perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

      This is an excellent point. What I actually wanted to do was 'count' the # of items that are assigned to the 'key' value. I have been burned by not being specific enough in the past, so I was trying to frame in a way that showed I had put some thought in the question.

      You could learn how to use map instead of trying to warn others away from it all the time because you don't understand it ...


      The way forward always starts with a minimal test.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (4)
As of 2024-04-24 06:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found