Removing a key from a Perl hash - perl

I have a hash in which its keys are hashes. I want to rename some of the keys inside the primary hash by adding a key with the desired name and deleting the unwanted key. I succeeded in adding a key, but I'm unable to delete the original key.
This statement isn't working
delete $primary_hash{$sec_hash_key};
If I print the value of $primary_hash{$sec_hash_key} it's returning $HASH(0X*). I don't know what is missing in syntax?

In Perl, hash keys are always strings. If you specify a non-string object as a hash key, perl will stringify it to be able to use it as a key. Therefore, when you say:
I have hash in which it's [sic] keys are hashes
you are wrong. They are not hashes, they are strings.
Now, if you did something like:
my %h = (a => 1);
my %g = (%h => 2);
That would have created %g as:
(a => 1, 2 => undef);
If, instead, you did %g = (\%h => 2), that would have created something along the lines of:
%g = (
'HASH(0x7ff92882cbd8)' => 2
);
Note that the key is a string. You cannot go back to the data structure from that string.

What do you mean by 'delete'? Free the memory, or just want the
key to be undefined, when checking for it in an if statement?
The latter you can achieve my setting the key undef.
$primary_hash{$sec_hash_key} = undef;.
But please provide a full working example of your problem, so
it can be reproduced.

Related

How to display hash table's values by delivering a array consist of hash table's keys in powershell?

$hash = #{}
$hash.x1 = 1
$hash.x2 = 2
Can I display the hash table's values like this?
$hash.[x1,x2]
$hash.[x1,x2] (with dot and bare words) will not work, but you can use the index operator directly on a hashtable with an array of the key names (as strings). Like this:
$hash['x1','x2']
or like this:
$keys = 'x1', 'x2'
$hash[$keys]

Perl Concatenating 2 hashes based on a certain key

Hi I have two hashes %Asset & %Activity
%Asset
Name,Computer Name
David,X
Clark,Y
Sam,Z
%Activity
Name,Activity
David,A
Clark,B
Sam,C
David,D
Clark,E
Sam,F
The second hash has the name repeated multiple times (can be more than 2) .. I want to get a hash with the concise infromation.. something like
Name,Computer Name,Activity
David,X,A&D
Clark,Y,B&E
Sam,Z,C&F
my idea in a pseudo code kind of way is;
foreach (#Activity{qw[Name]}) {
push #Asset{qw[Name Activity]}, $Activity['Activity']
}
What you want is a hash of hashes. Conceptually, you'd combine all information about an asset into a single hash.
my %dave = (
name => "Dave",
computer_name => "X",
activity => "A"
);
Then this goes into a larger hash of all assets keyed by their name.
$Assets{$dave{name}} = \%dave;
If you want to find Dave's activity...
print $Assets{Dave}{activity};
You can pull out all information about Dave and pass it around as a hash reference.
my $dave = $Assets{Dave};
print $dave->{activity};
This sort of structure inevitably leads to modelling your assets as objects.
You can learn more about hashes of hashes in the Perl Data Structures Cookbook.

join() function is returning the type followed by a hex number instead of a concatenated string

In essence, I want to take an array and create a single string with the elements of said array separated by a newline.
I have an array named $zones. Outputting the reference to $zones confirms it's an array.
The following code:
print_log(Dumper($zones));
print_log('-------');
print_log(Dumper(join("\n",$zones)));
results in the following output
[2013-06-15 16:23:29 -0500] info [dnsadmin] $VAR1 = [
'fake.com25',
'fake.com2',
'fake.com27',
'fake.com43',
'fake.com41',
'fake.com40',
'fake.com39',
'fake.com37',
'fake.com36',
'fake.com35',
'fake.com31',
'fake.com56',
'fake.com55',
'fake.com54',
'fake.com53',
'fake.com52',
'fake.com51',
'fake.com50',
'fake.com49',
'fake.com48',
'fake.com42',
'fake.com38',
'fake.com34',
'fake.com33',
'fake.com32',
'fake.com30',
'fake.com29',
'fake.com28',
'fake.com26',
'fake.com24',
'fake.com23',
'fake.com69',
'fake.com68',
'fake.com67',
'fake.com66',
'0',
'fake.com44',
'fake.com45',
'fake.com46',
'fake.com278'
];
[2013-06-15 16:23:29 -0500] info [dnsadmin] -------
[2013-06-15 16:23:29 -0500] info [dnsadmin] $VAR1 = 'ARRAY(0x170cf0d8)';
I really don't want to loop over this array manually. Can someone explain why the join() function is returning the name of the type along with a hex number?
How to do is explained well by user1937198, but why it works this way?
It's simple:
$zones is not an array. It's an array reference.
join works on lists. So if you do:
join("\n",$zones)
You essentially are calling join on a single-element list. And the element is a reference, which happens to stringify to ARRAY(0x170cf0d8).
To make it work correctly you have to dereference it, and it is done by prefixing with real datatype (# or %, or in some cases $).
This can be written like this: #$zones, or (some, including me, say that it's more readable) as: #{ $zones }.
This is important when you're having nested structures, because while you can have plain array as a variable, when you're dealing with nested data structures, it's always references.
what you want is join("\n",#{$zones}))
$zones is array reference and to join array values you have to dereference it first by prefixing scalar $zones with #
print_log(Dumper(join("\n",#$zones)));
For more info there is short tutorial on references:
http://perldoc.perl.org/perlreftut.html#NAME

Perl hash of hash of lists from Net::LDAP to a 'filtered' list

The Net::LDAP module for Perl provides an Net::LDAP::Search object. Its as_struct method returns the structure below.
Multiple entries as
$entry{dn=...} =
ref {cn} = ref {name}
ref {l} = ref {city}
ref{mail} = ref {xxxxxx}
An example:
uid=pieterb,ou=People,dc=example,dc=org {key of first hash = dn in ldap}
uid=pieterb {key=uid}
cn=Pieter B. {key=cn}
uidNumber=1000 {key=uidNumber}
gidNumber=4000 {key=gidNumber}
uid=markc,ou=People,dc=example,dc=org {key of first hash = dn in ldap }
uid=markc {key=uid}
cn=Mark Cole {key=cn}
uidNumber=1001 {key=uidNumber}
gidNumber=4000 {key=gidNumber}
However, the interface uses UI::Dialog which expects a list in the format below (radiolist/checklist), with data coming from the attribute values in the LDAP server
list => [
'Pieter B.', ['uid=pieterb,ou=People,dc=example,dc=org',0],
'Mark Cole', ['uid=markc,ou=People,dc=example,dc=org',0],
'cn_value(openldap)',['dn_value',0],
'givenname_value(activedirectory)',['dn_value',0]
]
It is very hard to guess what you want, but I think it is a list of the LDAP attribute names versus their values.
You should look at Data::Dumper to examine and present the data structures you are dealing with.
You don't mention what to do if the data you get from the search contains multiple Distinguished Names, or multiple values for an attribute, but this code simply takes the first DN and the first value in lists of attribute values to generate a list of lists.
I have little doubt that this isn't exactly what you need, and if you specify your requirement better we will be able to help further.
my $data = $msg->as_struct;
my $entry = (values %$data)[0];
my #attributes = map {
$_, [$entry->{$_}[0], 0]
} keys %$entry;
$dialog->checklist(list => \#attributes);

Cryptographic hash (sha1 or md5) of data given as a string in Mathematica

The sha1 hash of "abc" is
a9993e364706816aba3e25717850c26c9cd0d89d
The only way to get Mathematica to tell you that with its Hash function is
Hash[abc, "SHA"] // IntegerString[#, 16]&
(The IntegerString thing is just to output it in hex like most implementations do.)
Note that
Hash["abc", "SHA"]
gives the hash of "\"abc\"" -- not what you want!
In fact, the only reason we could get the correct hash of "abc" was because the Mathematica representation of the symbol abc happens to be the string "abc".
For the vast majority of strings, this will not be the case.
So how do you take the hash of an arbitrary string in Mathematica?
You can do it less kludgily by using StringToStream and the fact that FileHash can take an input stream as an argument. Then your sha1 function becomes:
sha1[s_String] := Module[{stream = StringToStream[s], hash},
hash = FileHash[stream,"SHA"];
Close[stream];
hash]
Here's a kludge that works. Write the string to a temp file and use FileHash:
sha1[s_String] := Module[{stream, file, hash},
stream = OpenWrite[];
WriteString[stream, s];
file = Close[stream];
hash = FileHash[file, "SHA"];
DeleteFile[file];
hash]
You might also want to define
hex = IntegerString[#, 16]&;
and return hex#hash in the above function.