I am novice in php development and I need your help.
I have read the column of a file and I want to keep in an array
only the distinct values
I do it with this code in a while (fgetcsv) loop
$sex_array = array();
isset($sex_array[$sex])?$sex_array[$sex]++:$sex_array[$sex]=1;
my array is in format
Array ( [man] => 33 [woman] => 141 )
How can I make a variable and when I print it to take
man:33,woman:141
I tried implode but I take 33,141
look at foreach taken from the page:
foreach ($a as $k => $v) {
echo "\$a[$k] => $v.\n";
}
Related
I have a question regarding duplicate keys in hashes.
Say my dataset looks something like this:
>Mammals
Cats
>Fish
Clownfish
>Birds
Parrots
>Mammals
Dogs
>Reptiles
Snakes
>Reptiles
Snakes
What I would like to get out of my script is a hash that looks like this:
$VAR1 = {
'Birds' => 'Parrots',
'Mammals' => 'Dogs', 'Cats',
'Fish' => 'Clownfish',
'Reptiles' => 'Snakes'
};
I found a possible answer here (https://www.perlmonks.org/?node_id=1116320). However I am not sure how to identify the values and the duplicates with the format of my dataset.
Here's the code that I have been using:
use Data::Dumper;
open($fh, "<", $file) || die "Could not open file $file $!/n";
while (<$fh>) {
chomp;
if($_ =~ /^>(.+)/){
$group = $1;
$animals{$group} = "";
next;
}
$animals{$group} .= $_;
push #{$group (keys %animals)}, $animals{$group};
}
print Dumper(\%animals);
When I execute it the push function does not seem to work as the output from this command is the same as when the command is absent (in the duplicate "Mammal" group, it will replace the cat with the dog instead of having both as arrays within the same group).
Any suggestions as to what I am doing wrong would be highly appreciated.
Thanks !
You're very close here. We can't get exactly the output you want from Data::Dumper because hashes can only have one value per key. The easiest way to fix that is to assign a reference to an array to the key and add things to it. But since you want to eliminate the duplicates as well, it's easier to build hashes as an intermediate representation then transform them to arrays:
use Data::Dumper;
my $file = "animals.txt";
open($fh, "<", $file) || die "Could not open file $file $!/n";
while (<$fh>) {
chomp;
if(/^>(.+)/){
$group = $1;
next;
}
$animals{$group} = {} unless exists $animals{$group};
$animals{$group}->{$_} = 1;
}
# Transform the hashes to arrays
foreach my $group (keys %animals) {
# Make the hash into an array of its keys
$animals{$group} = [ sort keys %{$animals{$group}} ];
# Throw away the array if we only have one thing
$animals{$group} = $animals{$group}->[0] if #{ $animals{$group} } == 1;
}
print Dumper(\%animals);
Result is
$VAR1 = {
'Reptiles' => 'Snakes',
'Fish' => 'Clownfish',
'Birds' => 'Parrots',
'Mammals' => [
'Cats',
'Dogs'
]
};
which is as close as you can get to what you had as your desired output.
For ease in processing the ingested data, it may actually be easier to not throw away the arrays in the one-element case so that every entry in the hash can be processed the same way (they're all references to arrays, no matter how many things are in them). Otherwise you've added a conditional to strip out the arrays, and you have to add another conditional test in your processing code to check
if (ref $item) {
# This is an anonymous array
} else {
# This is just a single entry
}
and it's easier to just have one path there instead of two, even if the else just wraps the single item into an array again. Leave them as arrays (delete the $animals{$group} = $animals{$group}->[0] line) and you'll be fine.
Given:
__DATA__
>Mammals
Cats
>Fish
Clownfish
>Birds
Parrots
>Mammals
Dogs
>Reptiles
Snakes
>Reptiles
Snakes
(at the end of the source code or a file with that content)
If you are willing to slurp the file, you can do something with a regex and a HoH like this:
use Data::Dumper;
use warnings;
use strict;
my %animals;
my $s;
while(<DATA>){
$s.=$_;
}
while($s=~/^>(.*)\R(.*)/mg){
++$animals{$1}{$2};
}
print Dumper(\%animals);
Prints:
$VAR1 = {
'Mammals' => {
'Cats' => 1,
'Dogs' => 1
},
'Birds' => {
'Parrots' => 1
},
'Fish' => {
'Clownfish' => 1
},
'Reptiles' => {
'Snakes' => 2
}
};
Which you can arrive to your format with this complete Perl program:
$s.=$_ while(<DATA>);
++$animals{$1}{$2} while($s=~/^>(.*)\R(.*)/mg);
while ((my $k, my $v) = each (%animals)) {
print "$k: ". join(", ", keys($v)) . "\n";
}
Prints:
Fish: Clownfish
Birds: Parrots
Mammals: Cats, Dogs
Reptiles: Snakes
(Know that the output order may be different than file order since Perl hashes do not maintain insertion order...)
I have an array of hashes (AoH) which looks like this:
$VAR1 = [
{
'Unit' => 'M',
'Size' => '321',
'User' => 'test'
}
{
'Unit' => 'M'
'Size' => '0.24'
'User' => 'test1'
}
...
];
How do I write my AoH to a CSV file with separators, to get the following result:
test;321M
test1;0.24M
I've already tried this code:
my $csv = Text::CSV->new ( { sep_char => ';' } );
$csv->print( $fh1, \#homefoldersize );
But I get
HASH(0x....)
in my CSV file.
Pretty fundamentally - CSV is an array based data structure - it's a vaguely enhanced version of join. But the thing you need for this job is print_hr from Text::CSV.
First you need to set your header order:
$csv->column_names (#names); # Set column names for getline_hr ()
Then you can use
$csv -> print_hr ( *STDOUT, $hashref );
E.g.
$csv -> column_names ( qw ( User Size Unit ) );
foreach my $hashref ( #homefoldersize ) {
$csv -> print_hr ( *STDOUT, $hashref );
}
As you want to concatenate a couple of your columns though, that's slightly harder - you'll need to transform the data first, because otherwise Size and Unit are separate columns.
foreach my $hashref ( #homefoldersize ) {
$hashref -> {Size} .= $hashref -> {Unit};
delete $hashref -> {Unit};
}
Additionally -as another poster notes - you'll need to set sep_char to change the delimiter to ;.
As an alternative to that - you could probably use a hash slice:
#values = #hash{#keys};
But print_hr does pretty much the same thing.
All that is necessary is
printf "%s;%s%s\n", #{$_}{qw/ User Size Unit /} for #homefoldersize;
Try using the example for Text::CSV posted here: http://search.cpan.org/~makamaka/Text-CSV-1.33/lib/Text/CSV.pm
You will need to set sep_char = ';' to make it semicolon-separated.
Am I doing this right?
my $variable = "hello,world";
my #somearray = split(',',$variable);
my %hash = ( 'somevalue' => #somearray);
foreach my $key ( keys %hash ) {
print $key;
foreach my $value ( #{$hash{$key}} ) {
print $value; #the value is not being read/printed
}
}
I don't know if I'm accessing the array that is stored in the hash for the particular value
You've been bitten by perl's flattening nature of lists. You see, when you do:
my %hash = ('somekey' => #somearray), perl converts that into a list form of hash assignment. So, what perl actually sees is:
my %hash = ('somekey' => 'hello', 'world' => ''); # I have put '' for simplicity, though it might well be `undef`
So, the next time you look up by 'somekey', you end up getting the string 'hello' and not the array "['hello', 'world']"
To fix this, you can use references. perlref can help you there for more information.
my %hash = ('somekey' => \#somearray);
# $hash{'somekey'} is an array reference now.
# So you use the pointy lookup syntax.
print $hash{'somekey'}->[0];
Another useful tool in visualising data structures is using the module Data::Dumper. It's available in the perl core distribution. Using it is as simple as doing:
use Data::Dumper;
print Dumper \%hash; # remember to pass in a reference to the actual datastructure, not the data structure itself.
Have fun!
This is wrong:
my %hash = ( 'somevalue' => #somearray);
The array is "flattened" to a list, so the line is equivalent to
my %hash = qw( somevalue hello world );
You need an array reference to create the inner array:
my %hash = ( 'somevalue' => \#somearray);
So you wanted to create a hash of array data structure. Something like this will also work.
my $variable = "hello,world";
my #somearray = split(',',$variable);
my %hash;
#my %hash = ( 'somevalue' => #somearray);
push (#{$hash{'somevalue'}},#somearray); #Storing it in a hash of array
foreach my $key ( keys %hash ) {
print $key;
foreach my $value ( #{$hash{$key}} ) {
print $value; #the value is not being read/printed
}
}
i have a form data and the data's array like this:
$datas=array("x-1","y-2","y-2","y-3","t-1");
my foreach loop:
foreach($datas as $x => $data){
$data=explode("-",$data);
if($data[0]==$data[0]+1){$n=1;}else{$n=0;}
$keys[$x]=$data[0].$n++;
$vals[$x]=$data[1];
}
i couldn't write the true code, my 3rd line is wrong i think (if($data[0]=$data[0]+1){$n="1";}else{$n="";})
so, i wanna rename the duplicate keys by giving number. my output should be like this:
x=1 y1=1 y2=2 y3=2 t1=1
Try
$datas=array("x-1","y-2","y-2","y-3","t-1");
$i=0;
$n=1;
foreach($datas as $x => $data){
$data=explode("-",$data);
$data2=explode("-",$datas[$i+1]);
if($data[0]==$data2[0])
{
$keys[$x]=$data[0].$n;
$n=$n+1;
}
else
{
$keys[$x]=$data[0].$n;
$n=0;
}
$vals[$x]=$data[1];
$i++;
}
This code has error you use = Which will assign value , not compare it.
also n should be integer not string
To fix that
foreach($datas as $x => $data){
$data=explode("-",$data);
if($keys[$x]==$keys[$x+1]){$n=1;}else{$n=0;}
$keys[$x]=$data[0].$n++;
$vals[$x]=$data[1];
}
if($data[0]=$data[0]+1){$n="1";}else{$n="";}
Use == instead of = for the if statements
I add my session variables like this:
foreach ( $data as $key => $value ) {
$this->Session->write("MyVariable.$key", $value );
}
Is it possible to add element to session variable array without passing the key ?
I mean like this:
$MyArray[] = "apple";
$MyArray[] = "banana";
So is it possible to add like this? Pseudo code:
$this->Session->write('MyVariable'.[], "apple");
$this->Session->write('MyVariable'.[], "banana");
Edit: $data array was for giving an example. The data that will be saved is not array. It is a string. Everytime I add to session variable I don't want to give key by code. I wonder whether is it possible out of the box. In my current codes I make it like this:
$newKey = count( $this->Session->read("MyVariable") );
$this->Session->write("MyVariable.$newKey", "apple");
Hi i guess it should be like this:
foreach ( $data as $key => $value ) {
$this->Session->write('MyVariable.'.$key, $value );
}
You have to place a dot inside the quotation mark.
If you don't want to give the key value each time, then store it as an array like #mark said
$this->Session->write("MyVariable", $data);
If you want to add a new value to the $data array in some other part of your code, you'll have to do something like
$data = $this->Session->read("MyVariable");
$data[] = array('other'=>'value');
$this->Session->write("MyVariable", $data);
Or add the exact key like #mmahgoub said
$this->Session->write("MyVariable".$key, $value);