Re: screen out an untained array from a special array
by hbm (Hermit) on Feb 08, 2009 at 01:55 UTC
|
use strict;
use warnings;
my @a = qw(0 6:4 12:8 19:31);
my %b;
for (@a){
if (!/:/){
$b{$_}=1;
} else {
my($a,$b) = split(/:/, $_);
($a,$b)=($b,$a) if $a>$b;
$b{$_}=1 for($a..$b);
}
}
print join(" ", grep {!exists $b{$_}} (0..31)), "\n";
Update:
In avoidance of tax filing, I carried on... You asked for 13:18, and later 18:13. This converts 0 6:4 12:8 19:31 to 1:3 7 13:18.
use strict;
use warnings;
my @a = qw(0 6:4 12:8 19:31);
my $s = '';
vec($s,0,32) = 0;
for (@a){
if (/(\d+):(\d+)/){
vec($s,$_,1) = 1 for(($1<$2) ? $1..$2 : $2..$1);
} else {
vec($s,$_,1) = 1;
}
}
my @bits = split(//,unpack("b*",$s));
my $series = 0;
for(0..31){
if ($bits[$_] eq 0) {
if (!$series) {
print;
$series = $_;
}
} else {
if ($series) {
print ( ($series+1 < $_) ? ':'.($_-1).' ' : ' ');
}
$series = 0;
}
}
| [reply] [d/l] [select] |
|
|
Yes, the output is: 1 2 3 7 13 14 15 16 17 18
can it be showed like: '3:1' '7' '18:13'?
You know the format conversion is what the difficulty lies.
| [reply] |
|
|
can it be showed like: '3:1' '7' '18:13'?
Of course it can! This is probably where you should start trying to write the code yourself. Since you requested some hints in your OP, take the hash that other monks have shown you and loop through the sorted keys.
| [reply] |
|
|
| [reply] |
|
|
Oh, what a nice solution. Thanks.
But if the output is the single digit series, it might be printed together. Say the input is: 1 9:2 21:10, 22:30, the outpout is: 031 (instead of 0, 31). Anyway, it's not a big deal.
| [reply] |
|
|
| [reply] |
Re: screen out an untained array from a special array
by graff (Chancellor) on Feb 08, 2009 at 02:09 UTC
|
Have you tried writing any code for that yet? I do understand the question, although the nature of the input is still a bit vague. Are you reading from a file? Is the max value always 31, or will it vary with the input?
If I had to code something like that, the plan would be:
use strict;
use warnings;
# get the inputs into an array, one "number" or "n:n" range per array
+element.
# then:
my @covered; # an array to track the "coverage" of the inputs
# for each input array element {
# if the element does not contain ":"
# use it as an array index and set $covered[$element] to some va
+lue
# otherwise
# split on ":", sort the pieces numerically and assign to $begin
+, $end
# $covered[$_] = 'some value' for ( $begin .. $end );
# }
# Once that's done, the only thing left to do is:
my $uncovered = '';
for ( 0 .. $#covered ) {
$uncovered .= "$_, " unless ( defined( $covered[$_] ));
}
$uncovered =~ s/, $/\n/;
print $uncovered;
That output would not exactly match what you said you wanted, but I'm puzzled why you would want your output to be so irregular (some elements shown as single values, some shown as ranges, some ranges have higher value first, etc).
If you really want your output to be as complicated as you say in the OP, go ahead and try writing some code to do that. If it doesn't work and you can't figure out how to fix it, post another thread, and show us what you tried. | [reply] [d/l] |
|
|
Thanks for everyone above replied.
The max value is always 31, and those input are read from a parsed file.
The output should be (\d+:\d+) so which is required by the Verilog syntax I had to use.
Here is what I have tried.
sub get_reserved {
my $bits_ref = shift;
my @bits = @{$bits_ref};
my @digits = map {
chomp;
if ( m/(\d+):(\d+)/) {
($1 > $2) ? ($2 .. $1) : ($1 .. $2);
}
else {
$_;
}
} @bits;
my @reg32set = map {0} 0 .. 31;
my @index;
if (@digits ne '') {
map {$reg32set[$_] = 1;} @digits;
@index = grep {if ($reg32set[$_] == 0) {$_;}} 0..31;
}
else {
undef @index;
}
}
| [reply] [d/l] |
|
|
The output should be (\d+:\d+) so which is required by the Verilog syntax I had to use.
Does the "Verilog syntax" have some sort of specification that says an N1..N2 range should be presented sometimes as "N1:N2" and other times as "N2:N1"? Do you know whether there is some reason for this fluctuation?
Regarding the code you posted, you are missing some fundamental points of Perl syntax. What do you think @digits ne '' is supposed to do? (Hint: an array in a scalar context always returns the number of elements in the array, which will never be the same as an empty string.)
If "Verilog syntax" supports the use of a consistent ordering of range components, I think this will be close to what you're looking for:
use strict;
use warnings;
my @test = qw/1 5:10 18:14 21 24:25 31:28/;
print get_reserved( \@test ), "\n";
sub get_reserved
{
my ( $bits_ref ) = @_; # should be an array ref
return "bad call to get_reserved()"
unless ( ref( $bits_ref ) eq 'ARRAY' and @$bits_ref );
my @reg32set;
for my $spec ( @$bits_ref ) {
if ( $spec =~ /(\d+):(\d+)/) {
my ( $bgn, $end ) = sort {$a<=>$b} ( $1, $2 );
$reg32set[$_] = 1 for ( $bgn .. $end );
}
else {
$reg32set[$spec] = 1;
}
}
my $verilog_string = '';
for my $seq ( 0 .. $#reg32set ) {
if ( defined( $reg32set[$seq] )) {
$verilog_string .= ", ";
} else {
$verilog_string .= "$seq:";
}
}
return "no intervals to report from get_reserved()"
unless ( $verilog_string =~ /\d/ );
$verilog_string =~ s/(?<=\d):[\d:]+:(?=\d)/:/g; # e.g. "2:3:4:5:6
+ -> 2:6
$verilog_string =~ s/^(?:, )+//;
$verilog_string =~ s/:(?:, )*$//;
$verilog_string =~ s/:,(?: ,)*/,/g;
return $verilog_string;
}
(updated to add diagnostic messages for a couple of edge conditions) | [reply] [d/l] [select] |
|
|
Re: screen out an untained array from a special array
by jwkrahn (Abbot) on Feb 08, 2009 at 06:05 UTC
|
Perhaps, another way to do it:
$ perl -le'
my @data = 0 .. 31;
my $input_data = "0, 6:4, 12:8 19:31";
my @input = sort { $b <=> $a } map { /(\d+):(\d+)/ ? $1 > $2 ? ( $2 ..
+ $1 ) : ( $1 .. $2 ) : $_ } $input_data =~ /\d+:\d+|\d+/g;
splice @data, $_, 1 for @input;
print for @data;
'
1
2
3
7
13
14
15
16
17
18
| [reply] [d/l] |
Re: screen out an untained array from a special array
by Lawliet (Curate) on Feb 08, 2009 at 01:23 UTC
|
Say I got a array ranging from 0 to 31 eg. 0, 6:2, 17:8 and 9:31 where digit means digit, (\d+):(\d+) means $2..$1 (or $1..$2 if $2>$1);
I want know which number is NOT listed in the array within 31:0.
input array : 0, 6:4, 12:8 and 19:31 (means: 0, 4, 5, 6, 8, .. 17, 19, 20 .. 31)
expected output: 3:1, 7, 13:18 (means: 1, 2, 3, 7, 13, 14 .. 17, 18)
What?
I am not in the mood to decipher that. Please read How (Not) To Ask A Question and then explain your question again.
And you didn't even know bears could type.
| [reply] |
|
|
IMO How (Not) To Ask A Question won't be able to help Hanken as much as you would like it to, self-evidently (and from browsing his home node), English isn't ever going to be the strong point - but we shouldn't hold that against them.
I admit I've read easier stuff, but I (think I) got there after not too long ...
IMO, the OP has, as its basis, an array of integers (each in the range 0 .. 31) - where sequences of consecutive numbers e.g. 2,3,4,5,6 can be shortened using a colon ':' e.g. 2:6 (but not necessarily in ascending order). The problem laid out in the OP can be summarised as the solving of the following 2 problems...
- expand the/any ranges (colon connected digit sequences) in the list.
- determine (and lists), numbers in the same range i.e. 0 .. 31, that are missing from i.e. don't appear in, the array (containing range expansions).
Update:
use warnings;
use strict;
my @data = qw/0 6:4 12:8 19:31/;
my %nums = map { ( $_ => undef ) } 0 .. 31;
map {
local @_ = sort { $a <=> $b } split /:/;
for (my $n = $_[0]; $n < ( @_ == 1 ? $_[0] + 1 : $_[1] + 1 ); $n++
+ ) {
delete $nums{$n};
}
} @data;
print "$_\n" foreach sort keys %nums;
A user level that continues to overstate my experience :-))
| [reply] [d/l] [select] |
|
|
| [reply] |
|
|
Sorry... I need to find a way to explain it.
| [reply] |
Re: screen out an untained array from a special array
by kennethk (Abbot) on Feb 08, 2009 at 01:43 UTC
|
I read your question to mean if you have a series of values in an array, how can you determine which values are not present. An easy implementation would use a hash. Assuming you have you values stored in @array, the following code would work:
my %value_hash = ();
foreach my $value (@array) {
$value_hash{$value} = 1;
}
for my $value (0 .. 31) {
if (not $value_hash{$value}) {
push @missing, $value;
}
}
| [reply] [d/l] [select] |
|
|
my @array = qw/0:2 4:6 8:12/;
my %hash;
foreach my $ele (@array) {
my @temp = split /:/, $ele;
$hash{$_}++ foreach $temp[0]..$temp[1];
}
I'll let the OP figure out how to deal with max:min pairs. The code I provided will only work for min:max pairs.
Updated with snippet. (I hope I did not do too much work for the OP.)
And you didn't even know bears could type.
| [reply] [d/l] |
|
|
O, there's someone finally understood my words and I am not alone :)
But, the input is not a simple digit, it may had the data like '3:0', '6:8' and also I need the output to be the same format.
| [reply] |
Re: screen out an untained array from a special array
by apl (Monsignor) on Feb 08, 2009 at 15:24 UTC
|
It's always been my opinion that you can't program a solution to a problem if you don't understand the problem. And if you can't explain the problem (clearly, cogently) you don't understand the problem.
Before you try to code, explain the solution to yourself, step by step. Assume computers don't exist, what are the steps you take to solve the problem. If you can do that, programming the solution is trivial. | [reply] |
|
|
Yes, I fully agree with apl. I think I need to understand more about my doubt and try to repeat it again and again clearly in my mind.
I have heard of a story of someone (maybe Larry??) that when he got a programming question, he did not ask someone else in the first but turn to his teddy bear, and he repeated his question to the teddy bear clear (and congently) times and times, and in most of time the answer will be prompted, it's more like an inpiration.
| [reply] |
|
|
| [reply] |
Re: screen out an untained array from a special array
by toolic (Bishop) on Mar 28, 2009 at 01:04 UTC
|
| [reply] |