Re: How to split a non even number of string elements into a hash
by Athanasius (Archbishop) on Feb 09, 2017 at 12:45 UTC
|
use strict;
use warnings;
use Data::Dumper;
my $string = "one 1 two 2 three 3 odd_element";
my @elements = split / /, $string;
push @elements, undef if @elements % 2;
my %hash = @elements;
print Dumper \%hash;
Output:
22:41 >perl 1750_SoPW.pl
$VAR1 = {
'three' => '3',
'odd_element' => undef,
'two' => '2',
'one' => '1'
};
22:42 >
Hope that helps,
| [reply] [d/l] [select] |
|
|
my @elements = split / /, $string;
my %hash = (@elements, (undef) x (@elements % 2));
($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord
}map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
| [reply] [d/l] [select] |
|
|
| [reply] [d/l] [select] |
Re: How to split a non even number of string elements into a hash
by Eily (Monsignor) on Feb 09, 2017 at 12:58 UTC
|
One other way to do it, which is to me a little more explicit, is to use m// in list context. This way you explicitly read your string two elements at a time. Since you will have as many elements in the return list as there are capture groups, even if they don't match, you can be sure to obtain an even sized list:
use Data::Dumper;
my $string = "one 1 two 2 three 3 odd";
my %hash = $string =~ /
(\w+) # one captured word
(?: # followed by
\s(\d+) # a space and a captured number
)? # in an optional non capturing gro
+up
/gx;
print Dumper \%hash;
__DATA__
$VAR1 = {
'three' => '3',
'two' => '2',
'one' => '1',
'odd' => undef
};
Edit: added the output | [reply] [d/l] |
|
|
| [reply] [d/l] [select] |
|
|
Hello
Eily
This is not a bad idea, but in cases that you will not need to parse a string beyond two elements at a time.
I will keep that in mind for possible further implementations in future.
Thank you for your time and effort reading and replying to my question.
Seeking for Perl wisdom...on the process of learning...not there...yet!
| [reply] [d/l] [select] |
|
|
If the answer Athanasius gave you is easier to understand for you, it's the one you should use. Writing code that you can understand and modify by yourself should be your priority. But if you have trouble understanding what I did in my answer and are curious, feel free to ask for further details.
| [reply] |
|
|
|
|
| [reply] [d/l] |
|
|
Re: How to split a non even number of string elements into a hash - update
by Discipulus (Canon) on Feb 09, 2017 at 12:43 UTC
|
hello thanos1983,
From my point of view what you are trying to achieve is simply wrong: hash are built of key - value pairs (where pair imply evenly) so why have something to over come something that must be true by definition?
To populate an hash you must provide even elements and if there are possibilities that elements are odd you must workaround and end with an even list, as you are doing in the second example.
PS: note also that the operation is always risky: the odd element must be the last one or the hash will be messed up.
PPS if you want to ignore odd element you can do somthing like this:
perl -MData::Dumper -we "while(my $k=shift @ARGV and $v = shift @ARGV
+){$h{$k}=$v};print Dumper \
%h" 1 a 2 b ODD
$VAR1 = {
'1' => 'a',
'2' => 'b'
};
OR play a trick with hash keys and scope to include a key with an undef value:
perl -MData::Dumper -we "my $k; while($k=shift @ARGV and $v = shift @A
+RGV ){$h{$k}=$v};$h{$k}= undef unless exists $h{$k}; print Dumper \%h
+ " 1 a 2 b ODD
$VAR1 = {
'1' => 'a',
'ODD' => undef,
'2' => 'b'
};
the above was wrong, this no:
perl -MData::Dumper -e "while($k=shift @ARGV and $v = shift @ARGV ){$h
+{$k}=$v};if($k and !$v){$h{$k}=undef}print Dumper \%h " 1 a 2 b ODD
$VAR1 = {
'1' => 'a',
'ODD' => undef,
'2' => 'b'
};
L*
There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
| [reply] [d/l] [select] |
|
|
Hello Discipulus
Thanks again for the time and effort. I agree with you, in theory it is not correct to have odd number of keys and values in a hash, but some times you have to bend the rules. :D
I just want to be sure that I am capturing all the possibilities in my script that all elements even odd ones will be captured and displayed in my hash. But yes I agree with you I should not "normally" have odd elements or at least process them with hash. But for my point of view it just makes it such easier to play around with them when all data are stored in a hash. :D
Thanks for the sample of code that you provided me with.
Seeking for Perl wisdom...on the process of learning...not there...yet!
| [reply] [d/l] [select] |
Re: How to split a non even number of string elements into a hash
by hippo (Archbishop) on Feb 09, 2017 at 12:49 UTC
|
If you don't want the warning, just silence it:
#!/usr/bin/perl
use strict;
use warnings;
no warnings 'misc';
use Data::Dumper;
my $str = "one 1 two 2 three 3 odd_element";
my %hash = split / /, $str;
print Dumper \%hash;
You can (and should), limit the scope of such silencing further.
This isn't to say that your initial situation doesn't smack of some deeper problem which maybe ought to be addressed. | [reply] [d/l] |
|
|
Hello
hippo
This is not a bad idea, but at the same time for my point of view not a good one. :D
Do not take me wrong, but I do not really want to silence warnings. There are there for some reason, even if you silence them temporarily and you enable them after.
But on the other hand in some rare cases it could be the only solution. In this case since the are work around solutions I would prefer to apply alternative solutions.
Thank you for your time and effort reading ans replying to my question though.
Seeking for Perl wisdom...on the process of learning...not there...yet!
| [reply] [d/l] [select] |
|
|
... I do not really want to silence warnings. There are there for some reason, even if you silence them temporarily and you enable them after.
And, of course, the reason in this case is to warn you about an unpaired key in a set of key/value pairs. But you want to accept an unpaired key, so if the oddball can only be at the end of the input string and if its default value is undef:
c:\@Work\Perl\monks>perl -le
"use strict;
use warnings;
use Data::Dumper;
;;
my %hash;
;;
my $str = 'one 1 two 2 three 3 odd_element';
{
no warnings 'misc';
%hash = split / /, $str;
}
print Dumper \%hash;
"
$VAR1 = {
'odd_element' => undef,
'three' => '3',
'one' => '1',
'two' => '2'
};
and you're done. KISS.
Update: Actually, the following is even KISSier and less messy:
my %hash = do {
no warnings 'misc';
split / /, $str;
};
I don't know why I didn't use it to begin with.
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
Re: How to split a non even number of string elements into a hash [RESOLVED]
by haukex (Archbishop) on Feb 09, 2017 at 16:06 UTC
|
Hi thanos1983,
In the spirit of TIMTOWTDI: just yesterday I published some code that uses m/\G.../gc to incrementally parse a string into a hash. The goal of that code is to parse a string like "RH= 23.8 %RH T= 20.4 'C Td= -1.0 'C Tdf=-0.9 'C a= 4.2 g/m3 x= 3.5 g/kg Tw= 10.2 'C ppm= 5635 pw= 5.68 hPa pws= 23.90 hPa h= 29.5 kJ/kg" (a line of data from a sensor I have to parse) into a data structure like { RH => { val=>23.8, unit=>"%RH" }, ... }. Although this is probably overkill for your case, note how it does allow for more powerful parsing of the input - in the aforementioned example, note how "ppm= 5635" doesn't have units, and how a simple split on whitespace won't work for "Tdf=-0.9".
If I apply the same principle to your code (slightly simplified):
use warnings;
use strict;
my $input = "one 1 two 2 three 3 odd_element";
my $REGEX = qr{ \s* \b (\w+) \s+ (\w+) \b \s* }msx;
my %output;
pos($input)=undef;
while ($input=~/\G$REGEX/gc) {
$output{$1} = $2;
}
my $rest = substr $input, pos $input;
if (length $rest) { # leftovers
$output{$rest} = 'turkeysandwich';
}
use Data::Dumper;
print Dumper(\%output);
__END__
$VAR1 = {
'one' => '1',
'two' => '2',
'three' => '3',
'odd_element' => 'turkeysandwich'
};
(Note: Assigning to pos is not needed in the example above, but it may become necessary if the code is embedded into a larger script that performs other regexes on the input that may modify pos.)
Hope this helps, -- Hauke D | [reply] [d/l] [select] |
Re: How to split a non even number of string elements into a hash [RESOLVED]
by kcott (Archbishop) on Feb 10, 2017 at 07:33 UTC
|
G'day thanos1983,
Instead of using intermediary variables, you could do this:
my %hash = ((split / /, $str), $str =~ y/ / / % 2 ? () : undef);
I tested this on the command line. Sorry about the wrapping.
$ perl -wMstrict -MData::Dump -e 'my $s = "a 1 b 2 c 3 Odd"; my %h = (
+(split / /, $s), $s =~ y/ / / % 2 ? () : undef); dd \%h'
{ a => 1, b => 2, c => 3, Odd => undef }
$ perl -wMstrict -MData::Dump -e 'my $s = "a 1 b 2 c 3 Even 4"; my %h
+= ((split / /, $s), $s =~ y/ / / % 2 ? () : undef); dd \%h'
{ a => 1, b => 2, c => 3, Even => 4 }
See "perlop: Quote-Like Operators"
if you're unfamiliar with using y/// for counting.
| [reply] [d/l] [select] |
|
|
Hello kcott,
Not a bad idea, I never thought about combining some many functions together also.
I will keep that in mind thank you for your time and effort.
Seeking for Perl wisdom...on the process of learning...not there...yet!
| [reply] [d/l] [select] |
Re: How to split a non even number of string elements into a hash [RESOLVED]
by Anonymous Monk on Feb 09, 2017 at 19:04 UTC
|
TMTOWTDI, although certainly not best way. :P
my $str = "one 1 two 2 three 3 odd_element";
my $cnt = () = $str =~ /(\s)/g; # count spaces
my %hash = split /\s/, $str, $cnt + 1; # split on spaces + 1
| [reply] [d/l] |
|
|
| [reply] [d/l] [select] |