How can I delete duplicate values across arrays stored in hash? - arrays

I have the following hash:
my %HASH = (
'List1' => [ 'the', 'red', 'cat', 'jumps' ],
'List2' => [ 'the', 'brown', 'fox', 'jumps' ],
'List3' => [ 'a', 'red', 'fox', 'jumps' ],
);
I want to delete duplicate elements across these arrays, so that only unique elements remain. The desired output would be the following:
my %HASH = (
'List1' => [ 'cat' ],
'List2' => [ 'brown' ],
'List3' => [ 'a' ],
);
In other words, if an element is present in both List1 and List2, it should be deleted from both lists.
I have tried to do the following:
use strict;
use warnings;
use diagnostics;
use Data::Dumper;
foreach my $key ( keys %HASH ) {
foreach ( #{$HASH{$key}} ) {
if(exists($HASH{$key})){
#{$HASH{$key}} = delete($HASH{$key});
}
}
}
print Dumper(\%HASH);
Which doesn't seem to do anything, the hash remains the way it was. I'm still pretty new to Perl, so I'm not sure where I went wrong with that. But Perldoc says that calling exists on array values is deprecated anyway, so any solution which uses something other than exists is welcome too!

use strict;
use warnings;
my %hash = (
'List1' => [ 'the', 'red', 'cat', 'jumps' ],
'List2' => [ 'the', 'brown', 'fox', 'jumps' ],
'List3' => [ 'a', 'red', 'fox', 'jumps' ],
);
# first, we count all words
my %count;
for my $words (values %hash) {
for my $word (#$words) {
$count{$word}++;
}
}
# Now, we filter the words with `grep` so that only
# those remain which were found once
for my $words (values %hash) {
#$words = grep { $count{$_} == 1 } #$words;
}
use Data::Dump;
dd \%hash;
Outputs:
{ List1 => ["cat"], List2 => ["brown"], List3 => ["a"] }

Related

Using join to concatenate array values

I have array values that is getting returned from SQL object.
my #keys = $db_obj->SelectAllArrayRef($sql);
print Dumper #keys;
gives
$VAR1 = [ [ '8853' ], [ '15141' ] ];
I need to create string from this array: 8853, 15141.
my $inVal = join(',', map { $_->[0] }, #$keys);
my $inVal;
foreach my $result (#$keys){
$inVal .= $result->[0];
}
my $inVal = join(',', #$keys);
Value i get is ARRAY(0x5265498),ARRAY(0x52654e0). I think its reference to the array. Any idea what am I missing here?
Don't pass arrays to Dumper; it leads to confusing output. $VAR1 is not a dump of #keys, it's a dump of $keys[0]. Instead, you should have done
print(Dumper(\#keys));
This would have given
$VAR1 = [ [ [ '8853' ], [ '15141' ] ] ];
The code you want is
join ',', map { $_->[0] }, #{ $keys[0] };
That said, it appears that ->SelectAllArrayRef returns a reference to the result, and so it should be called as follows:
my $keys = $db_obj->SelectAllArrayRef($sql);
For this,
print(Dumper($keys));
outputs
$VAR1 = [ [ '8853' ], [ '15141' ] ];
And you may use either of the methods you used in your question.
join ',', map { $_->[0] }, #$keys;
The first version should work for you:
my $arr = [ [ '8853' ], [ '15141' ] ];
my $values = join(',', map { $_->[0] } #$arr);
print $values . "\n";
8853,15141

Perl Array Order

I'am new with perl and stucked with the following exercise.
I have a multi-array and want order its element to descending to the inside arrays sum's.
I want to make the order with Schwartzian transform.
This is my vector:
my #vectors = ( [1], [ 1, 2, 3 ], [4], [ 2, 2, 1 ] );
This is the expected vector:
#sorted_vectors = ( [1,2,3], [2,2,1], [4], [1] );
So far I am tried with these:
(1)
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my #vectors = ( [1], [ 1, 2, 3 ], [4], [ 2, 2, 1 ] );
my #sorted_vectors;
# #sorted_vectors = ( [1,2,3], [2,2,1], [4], [1] );
my %hash=();
for(my $i=0;$i< scalar #vectors;$i++){
$hash{$i}=#vectors[$i];
}
for my $key ( sort { $hash{$b}[1] <=> $hash{$a}[1] } keys %hash ) {
push(#sorted_vectors,[#{$hash{$key}}]);
}
print Dumper( \#sorted_vectors );
(2)
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my #vectors = ( [1], [ 1, 2, 3 ], [4], [ 2, 2, 1 ] );
my #sorted_vectors;
# #sorted_vectors = ( [1,2,3], [2,2,1], [4], [1] );
my #sorted = map { $_->[0] }
sort { $a->[1] cmp $b->[1] }
map { [$_, foo($_)] }
#vectors;
sub foo{
my $res = 0;
foreach my $x (#_) {
$res+= $x;
}
return $res;
}
print Dumper(\#sorted);
Your code works with few alterations,
my #sorted = map { $_->[0] }
# sort { $a->[1] cmp $b->[1] } # string sort, ascending order
sort { $b->[1] <=> $a->[1] } # numeric sort, descending order
# map { [$_, foo($_)] } # foo() expects list, not array reference
map { [$_, foo(#$_)] } # dereferencing $_ aref for foo()
#vectors;
or same thing but using sum() from core module List::Util
use List::Util 'sum';
my #vectors = ( [1], [ 1, 2, 3 ], [4], [ 2, 2, 1 ] );
my #sorted_vectors = map $_->[0],
sort { $b->[1] <=> $a->[1] }
map [ $_, sum(#$_) ],
#vectors;
use Data::Dumper; print Dumper \#sorted_vectors;
output
$VAR1 = [
[
1,
2,
3
],
[
2,
2,
1
],
[
4
],
[
1
]
];
This is simple with List::UtilsBy::rev_nsort_by and List::Util::sum:
my #vectors = ( [1], [ 1, 2, 3 ], [4], [ 2, 2, 1 ] );
my #sorted = rev_nsort_by { sum #$_ } #vectors;
This sorts the list of #vectors in reverse numerical order (i.e. largest number first) of the result of its control block. The control block here simply sums all the individual elements of each component.

How can I get the last-level values in a Perl hash-of-hashes into one array [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
In Perl, from the below hash:
{
'item3' => {
'floors' => [ 'a', 'b', 'c' ]
},
'item1' => [ 'special' ]
'item2' => {
'books' => {
'topics' => [ 'epics' ]
},
'sports' => [ 'tennis' ]
},
'item5' => {
'groups' => {
'teams' => [ 'x', 'y' ]
}
},
'offers' => {
'list' => [ 'bags' ]
}
}
Need to parse only last values in each sub level of hash where it is always be an array.
Only final child entries(array values) need to be listed.
Expecting the output in one single array:
[ 'a', 'b', 'c', 'special', 'epics', 'tennis', 'x', 'y', 'bags' ]
no idea how to proceed....please help me to get rid of this.
Advance Thanks!!!!
Recursion assumes that data structure consists of hashes and arrays only, and array elements are not references,
use strict;
use warnings;
use Data::Dumper;
my %h;
#h{ 1..5 } = (
{ 'item3' => { 'floors' => [ 'a', 'b', 'c' ] } },
{ 'item1' => [ 'special' ] },
{ 'item2' => {
'books' => { 'topics' => [ 'epics' ] },
'sports' => [ 'tennis' ]
}},
{ 'item5' => { 'groups' => { 'teams' => [ 'x', 'y' ] } } },
{ 'offers' => { 'list' => [ 'bags' ] } },
);
print Dumper [ arrvals(\%h) ];
sub arrvals {
my ($ref) = #_;
return ref($ref) eq "ARRAY"
? #$ref
: map arrvals($_), values %$ref;
}

initialise list with every element is a an associative array and last elment of the associative array is two d array in perl?

I'm trying to create a database .Each element in list contains details in the form of associative array and the last element of each of these associative array is a 2-d array,i need help initializing it ..
You need to say much more about what it is you are trying to do, but this may help: it initialises a Perl data structure in the way you have described. Note that there can be no "last" element of a hash (a better name than "associative array") as hashes are unordered. I have used the customers field of the data to hold the 2D array you talked about.
use strict;
use warnings;
my #list = (
{
id => 1,
name => 'cattle',
customers => [
[ 'World Bank', 'Space Marines', 'Undersea Exploration' ],
[ 1, 2, 3 ],
[ 0.0500, 0.6322, 0.9930 ],
],
},
{
id => 2,
name => 'arable',
customers => [
[ 'Jack Spratt', 'Molly Malone', 'The Whistler' ],
[ 4, 5, 6 ],
[ 0.0022, 0.1130, 0.6930 ],
],
},
{
id => 3,
name => 'seafood',
customers => [
[ 'Tai Chi School of Fishery', 'Latin Intermediary College', 'Ping Pong Gymnastics' ],
[ 7, 8, 9 ],
[ 0.0012, 0.8540, 0.9817 ],
],
},
);

perl array of hashes using Tie::IxHash

I am trying to create an array of hashes with each has being an tied, ordered IxHash. When looping through my initial hash, the keys are indeed in order. However, as soon as I push them onto an array, the ordering disappears. I know this is my poor knowledge of what is happening with the hash when it is pushed on the array, but if somebody could enlighten me, it would be much appreciated.
#! /usr/bin/perl -w
use strict;
use Data::Dumper;
use Tie::IxHash;
my #portinfo;
tie (my %portconfig, 'Tie::IxHash',
'name' => [ 'Name', 'whatever' ],
'port' => [ 'Port', '12345' ],
'secure' => [ 'Secure', 'N' ]
);
print "Dump of hash\n";
print Dumper(%portconfig);
print "\nDump of array\n";
push #portinfo, {%portconfig};
print Dumper(#portinfo);
The output of this :-
Dump of hash
$VAR1 = 'name';
$VAR2 = [
'Name',
'whatever'
];
$VAR3 = 'port';
$VAR4 = [
'Port',
'12345'
];
$VAR5 = 'secure';
$VAR6 = [
'Secure',
'N'
];
Dump of array
$VAR1 = {
'secure' => [
'Secure',
'N'
],
'name' => [
'Name',
'whatever'
],
'port' => [
'Port',
'12345'
]
};
Your code:
push #portinfo, {%portconfig};
print Dumper(#portinfo);
takes the tied hash %portconfig and places its contents into a new anonymous hash which is then pushed into #portinfo. Thus, you have an anonymous, non-ordered hash in your array.
What you probably mean to do is
push #portinfo, \%portconfig;
print Dumper(#portinfo);
This pushes a reference to %portconfig into #portinfo, thereby retaining your required ordering.
Thus:
#! /usr/bin/perl -w
use strict;
use Data::Dumper;
use Tie::IxHash;
my #portinfo;
tie (my %portconfig, 'Tie::IxHash',
'name' => [ 'Name', 'whatever' ],
'port' => [ 'Port', '12345' ],
'secure' => [ 'Secure', 'N' ]
);
print "Dump of hash\n";
print Dumper(%portconfig);
print "\nDump of array\n";
push #portinfo, \%portconfig;
print Dumper(#portinfo);
Gives
C:\demos>perl demo.pl
Dump of hash
$VAR1 = 'name';
$VAR2 = [
'Name',
'whatever'
];
$VAR3 = 'port';
$VAR4 = [
'Port',
'12345'
];
$VAR5 = 'secure';
$VAR6 = [
'Secure',
'N'
];
Dump of array
$VAR1 = {
'name' => [
'Name',
'whatever'
],
'port' => [
'Port',
'12345'
],
'secure' => [
'Secure',
'N'
]
};

Resources