my %Hash = (
1111 => [5,6] ,
5555 => [3,4],
2222 => [3],
4444 => [3,1]
)
How can i sort hash by values in ascending order, so that all the values should display as sorting but if elements are equal , sorting of keys should be in descending order.
<p> Output:
1111 => 6
5,
5555 => 4
3 ,
4444 => 3
1 ,
2222 => 3
</p>
I don't know what you mean about descending order. Can you show an example? I'll go by the output you show.
I assumed that you didn't want to change the original data (which may not be the case) so I used the map-sort to create an intermediate one. I go through that intermediate result in order and do the fiddly bits to get what you want. Much of the ugliness is to get you the format you wanted.
The postfix dereference is useful here:
use v5.26;
use utf8;
use strict;
use warnings;
my %Hash = (
1111 => [5,6],
5555 => [3,4],
2222 => [3],
4444 => [3,1]
);
foreach my $tuple (
sort {
$b->[1][0] <=> $a->[1][0]
}
map {
[ $_, [ sort { $b <=> $a } $Hash{$_}->#* ] ];
}
keys %Hash
) {
print my $string = "$tuple->[0] => ";
my $indent = length $string;
foreach my $i ( 0 .. $tuple->[1]->$#* ) {
print ' ' x $indent if $i;
print $tuple->[1][$i];
print ',' if $i == $tuple->[1]->$#*;
print "\n";
}
}
This produces:
1111 => 6
5,
5555 => 4
3,
4444 => 3
1,
2222 => 3,
Related
I have a script that looped over to get the values $mac and $snr. The result of the loop is as follows
133.3133.5132.9133.1132.9131.8234.4233.7234.7230.3232.3230.8331.9332.0331.6331.6330.9330.2 itd.....
9437.39437.09436.79436.89435.19433.09535.29535.
result from $mac is bolt
result form $snr is next
how create %hash where result will be
my %hash = ( mac1 => [’snr1', ‘snr2', ‘snr3', ‘snr4', ‘snr5', ‘snr6'],
mac2 => [’snr1', ‘snr2', ‘snr3', ‘snr4', ‘snr5', ‘snr6'],
mac3 => [’snr1', ‘snr2', ‘snr3', ‘snr4', ‘snr5', ‘snr6'],
);
result with value
my %hash = ( 1 => [’33.3', ‘33.5', ‘32.9', ‘33.1', ‘32.9','31.8' ‘'],
2 => [’34.4', ‘33.7', ‘34.7', ‘30.3', ‘32.3', ‘30.8'],
3 => [’31.9', ‘32.0', ‘31.6', ‘31.6', ‘snr5', ‘snr6'],
);
I can put only part code:
I can put only part code:
my $db_snr = DBI->connect("DBI:mysql:$baza:$host", $user, $pass, { RaiseError=>'0', AutoCommit=>'1'} );
if(! $db_snr){
print LOG "Can't connect to mysql serwer at $host, skipping!\n";
exit 0;
}
foreach $upstrim (sort keys %interface){
$typ = $interface{$upstrim}[50];
$mac=$interface{$upstrim}[0];
$mac=~ s/MAC//;
print($snr)
print($mac) # here I woul like create hash witch array
if(($typ eq 'u') && ($mac =~ m/^\d/)){
my $snr = $interface{$upstrim}[30];
if (($snr < 11) && ($snr > 0)) {
print LOG "Test SNR nadajcy $cmts:$mac:$snr:$typ\n";
$db_snr->do("insert into snr values ('$cmts','$mac',NOW(),NOW(),'$snr','1','0','$upstrim') ON DUPLICATE KEY update snr='$snr' ,data_last=NOW(), licznik=licznik+1 ") or warn "Can't prepare: $DBI::errstr";
}
}
}
$db_snr->disconnect;
close(LOG);
You can just loop over the values, split the line, then use a push statement to add numbers to the hash value, like below. Note that I am using the infile handle DATA for simplicity here, you have to use your own file handle, or the <> operator.
use strict;
use warnings;
use Data::Dumper;
my %hash;
while (<DATA>) {
my ($mac, $snr) = split;
push #{ $hash{$mac} }, $snr;
}
print Dumper \%hash;
__DATA__
1 33,3
1 33.2
1 33.3
1 32.7
1 32.9
1 32.5
1 31.7
2 34.4
2 34.9
2 34.6
2 34.3
2 33.5
2 30.8
3 31.9
3 32.0
3 31.8
3 31.7
3 31.4
3 30.4
95 34.8
96 30.6
96 31.8
96 33.4
96 34.2
96 34.0
96 29.5
Output:
$VAR1 = {
'3' => [
'31.9',
'32.0',
'31.8',
'31.7',
'31.4',
'30.4'
],
'1' => [
'33,3',
'33.2',
'33.3',
'32.7',
'32.9',
'32.5',
'31.7'
],
'2' => [
'34.4',
'34.9',
'34.6',
'34.3',
'33.5',
'30.8'
],
'96' => [
'30.6',
'31.8',
'33.4',
'34.2',
'34.0',
'29.5'
],
'95' => [
'34.8'
]
};
I have a hash that I want to sort the keys numerically in ascending order and
its values in ascending alphabetically manner.
#!/usr/bin/perl
use warnings;
use strict;
use List::MoreUtils;
use Tie::IxHash;
my %KEY_VALUE;
#tie %KEY_VALUE,'Tie::IxHash';
my %KEY_VALUE= (
0 => [ 'A', 'C', 'B', 'A' ,'D'],
5 => [ 'D', 'F', 'E', ],
2 => [ 'Z', 'X', 'Y' ],
4 => [ 'E', 'R', 'M' ],
3 => [ 'A', 'B', 'B', 'A' ],
1 => [ 'C', 'C', 'F', 'E' ],
);
#while (my ($k, $av) = each %KEY_VALUE)
#{
# print "$k #$av\n ";
#}
#Sort the key numerically
foreach my $key (sort keys %KEY_VALUE)
{
print "$key\n";
}
#To sort the value alphabetically
foreach my $key (sort {$KEY_VALUE{$a} cmp $KEY_VALUE{$b}} keys %KEY_VALUE){
print "$key: $KEY_VALUE{$key}\n";
}
The wanted input is like this, and I want to print out the sorted keys and values.
%KEY_VALUE= (
0 => [ 'A','A','B','C','D'],
1 => [ 'C','C','E','F' ],
2 => [ 'X','Y','Z' ],
3 => [ 'A', 'A', 'B', 'B' ],
4 => [ 'E','M','R' ],
5 => [ 'D','E','F', ],
);
Additional problem, how to print the key and the scalar value of the first different value
Wanted Output:
KEY= 0 VALUE:0 2 3 4 #The scalar value of first A B C D, start with 0
KEY= 1 VALUE:0 2 3 #The scalar value of first C E F
KEY= 2 VALUE:0 1 2 #The scalar value of first X Y Z
KEY= 3 VALUE:0 2 #The scalar value of first A B
KEY= 4 VALUE:0 1 2 #The scalar value of first E M R
KEY= 5 VALUE:0 1 2 #The scalar value of first D E F
Hash keys have no defined order. Generally you sort the keys as you're iterating through the hash.
The values can be sorted as you iterate through the hash.
# Iterate through the keys in numeric order.
for my $key (sort {$a <=> $b } keys %hash) {
# Get the value
my $val = $hash{$key};
# Sort it in place
#$val = sort { $a cmp $b } #$val;
# Display it
say "$key -> #$val";
}
Note that by default sort sorts in ASCII order as strings. That means sort keys %KEY_VALUE is not sorting as numbers but as strings. sort(2,3,10) is (10,2,3). "10" is less than "2" like "ah" is less than "b". Be sure to use sort { $a <=> $b } for numeric sorting and sort { $a cmp $b } for strings.
You could use a different data structure such as Tie::Ixhash though tying has a significant performance penalty. Generally it's better to sort in place unless your hash gets very large.
You can't sort a hash, you can at best print it sorted (or keep the sorted keys in another array). Finding the position of the first value can be done with first_index; we remove duplicates with uniq.
foreach my $key (sort keys %KEY_VALUE) {
my #value = #{$KEY_VALUE{$key}};
my #indices = map { my $e = $_; first_index { $_ eq $e } #value } (uniq (sort #value));
print "$key: " . (join ', ', #indices) . "\n";
}
How can I print a hash in Perl, such that 3 key value pairs are printed on each line?
print %hash;
This will print key value pairs each in a line.
To display the hash, so "that 3[n] key value pairs are printed on each line", you can use a counter ($n) and % (modulo op) to determine when to print a "\n". Demo:
use Modern::Perl;
my %h = ();
for (0..7) {
$h{$_} = chr(65 + $_);
}
print %h, "\n";
my $cols = +$ARGV[0] || 5;
my $n = -$cols;
for my $key (keys %h) {
print $key, ' => ', $h{$key}, 0 == ++$n % $cols ? "\n" : "\t\t";
}
print $n % $cols ? "\n------" : "------";
output:
perl -w 31444449.pl 1
6G4E1B3D0A7H2C5F
6 => G
4 => E
1 => B
3 => D
0 => A
7 => H
2 => C
5 => F
------
perl -w 31444449.pl
6G4E1B3D0A7H2C5F
6 => G 4 => E 1 => B 3 => D 0 => A
7 => H 2 => C 5 => F
------
perl -w 31444449.pl 3
6G4E1B3D0A7H2C5F
6 => G 4 => E 1 => B
3 => D 0 => A 7 => H
2 => C 5 => F
------
Borodin's solutions, however, is simpler.
See mpapec answer for a much improved version.
A very simple way to do this is to copy all the keys and values to an array, and then print six (three pairs) of those at a time
use strict;
use warnings;
my %h = map { $_ => 1 } 'A' .. 'H';
my #kv = %h;
while ( my #row = splice #kv, 0, 6 ) {
print "#row\n";
}
output
B 1 C 1 A 1
D 1 E 1 G 1
F 1 H 1
You can use natatime from List::MoreUtils:
use List::MoreUtils qw/natatime/;
my $it = natatime 6, %ENV;
while (my #vals = $it->()) {
print "#vals\n";
}
List::MoreUtils isn't in core modules, you need to install it.
Thanks All. I tried this and it worked.
my #keylist=sort keys %hash;
my $counter=0;
foreach(#keylist){
#printing the key value pairs
printf "%-15s :%3d ",$_,$hash{$_};
$counter++;
if($counter==3){
$counter=0;
print "\n";
}
}
print "\n";
If you really just want to print hash and check the values for debugging or for analysing then use
use Data::Dumper;
print Dumper(\%hash);
This print hash keys and values at any n number of levels
I have a hash of arrays (HoA). I have been processing the values of this HoA using $arrayrefs. However, now I need to retrieve the $key based on the $arrayrefs.
my %a = ( 1 => "ONE" ,
2 => "TWO" ,
3 => " Three", );
my %aa = ( 4 => [ 'ONE' , 'TWO', 'THREE'],
5 => ['one' , 'two', 'three'],
6 => ['more', 'dos', 'some'],
);
my #array = ('ONE' , 'TWO', 'THREE');
my $array_ref = \#array;
# returns the $key where the $value is 'ONE'
my ($any_match) = grep { $a{$_} eq 'ONE' } keys %a;
print $any_match."\n"; # this returns '1', as expected.. Good!
my ($match) = grep { $aa{$_} eq #$array_ref } keys %aa;
print $match."\n"; # <--- error: says that match is uninitialized
In the last print statement, I would like it to return 4. Does anyone know how to do this?
You can't compare arrays with eq. A simple solution is to turn both arrays into strings and comparing the strings using eq:
my ($match) = grep { join("", #{$aa{$_}}) eq join("", #$array_ref) } keys %aa;
For comparing arrays you could also utilize one of many modules from CPAN, e.g. Array::Compare, List::Compare, etc.
Always use strict; use warnings;. Add use v5.10; since Perl's (v5.10+) smart matching will be used to compare arrays. Do the following:
my ($match) = grep { #{$aa{$_}} ~~ #$array_ref } keys %aa;
The smart operator ~~ is used here to compare the arrays.
I am new to perl. I want to store the values corresponding to the keys in the following fashion. Please see below for a sample input data. Could someone help me to do this in perl.
output:
key value
1 (11, 20)
2 (17, 15)
3 (10, 11)
Input data:
key value
2 17
3 10
1 11
1 20
2 15
3 11
You can store the data in a hash-of-arrays structure (perldoc perldsc):
use warnings;
use strict;
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
my %data;
while (<DATA>) {
my ($k, $v) = split;
push #{ $data{$k} } , $v;
}
print Dumper(\%data);
=for output
$VAR1 = {
'1' => [
'11',
'20'
],
'2' => [
'17',
'15'
],
'3' => [
'10',
'11'
]
};
=cut
__DATA__
2 17
3 10
1 11
1 20
2 15
3 11
Assuming that each of the lines in the input data is in
a string, use a hash which has unique keys by definition.
If the key exists in the hash push the value onto the arrayref.
If it doesn't exist assign an array reference to the key with the
value. Next time that key appears you'll push the value onto the arrayref.
my $hash = {};
foreach my $line ( #lines ) {
my ($key, $val) = split(/\s/, $line);
if( $hash->{$key} ) {
push( #{ $hash->{ $key } }, $val );
}
else {
$hash->{$key} = [ $val ];
}
}
Using oneliner:
$ echo "key value
2 17
3 10
1 11
1 20
2 15
3 11" | perl -anE'next if 1..1;push#{$h{$F[0]}},$F[1]}{say"key value";$"=", ";say"$_ (#{$h{$_}})"for sort{$a<=>$b}keys%h'
key value
1 (11, 20)
2 (17, 15)
3 (10, 11)