Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Generating a chart 2

Status
Not open for further replies.

nfaber

Technical User
Oct 22, 2001
446
US
Hello all,

I am in the process of writing some code that generates a chart. I can probably figure this out, but I though someone might have some ideas on an easy way to do this and want to poke at some code on a Sunday. The chart needs to look like this:

Code:
troubleNumber chart:
devType, critical, warning, normal
router, 27, 2, 3
switch, 3, 5, 7,

I need to count all the severities of tickets for each device type in an array. The array looks like this called @type_chart that contains the type (ex, router) and the severity (ex, normal) for each ticket:
Code:
server,normal
server,normal
server,normal
server,normal
server,normal
pc,normal
server,warning
server,normal
server,normal
server,normal
pc,normal
server,normal
server,normal
server,normal
pc,normal
server,critical
server,normal
server,normal
server,normal
router,normal
router,normal
server,normal
server,normal
server,normal
server,normal
server,normal
router,critical
server,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,critical
server,normal
server,warning
server,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,normal
pc,normal
pc,normal
pc,normal
server,normal
server,normal
pc,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,critical
server,normal
server,normal
server,normal
server,normal
pc,normal
server,normal
server,warning
pc,normal
server,normal
server,warning
server,normal
server,normal
server,normal
server,normal
router,normal
server,normal
server,normal
router,normal
server,normal
server,warning
server,normal
server,normal
router,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,critical
server,normal
pc,warning
server,normal
server,normal
server,normal
pc,warning
server,warning
server,normal
server,normal
server,critical
server,normal
pc,normal
server,normal
server,normal
pc,normal
server,normal
server,normal
server,normal
server,normal
pc,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,warning
server,normal
server,warning
server,normal
pc,normal
server,critical
pc,normal
server,normal
server,normal
server,normal
server,normal
pc,normal
server,normal
server,normal
server,warning
server,normal
server,normal
pc,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,critical
pc,warning
server,normal
server,normal
server,normal
pc,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,normal
server,warning
server,normal
server,normal
server,warning
server,warning
server,normal
server,critical
server,normal
server,normal
server,normal
server,critical
pc,normal
server,normal
server,normal

Here is the code I have so far:

Code:
push (@type_chart, join (',',$type,$severity_code);
my %prob_type =();
my @type_critical = ();
my @type_warning = ();
my @type_normal = ();
foreach (@type_chart) {
	my ($typ,$cri) = split (/,/);
	#print "$_\n";
	if ($_ =~ /critical/i) { push (@type_critical, $_);}
	if ($_ =~ /warning/i) { push (@type_warning, $_);}
	if ($_ =~ /normal/i) { push (@type_normal, $_);}
}
foreach $type_new (@types_new) {
	foreach $var1 (@type_critical) {
		next unless $var1 =~ /$type_new/;
		$prob_type{$var1}++;
	}
}
# print records to file
print LOG "Problem Types and counts\n";
foreach ( keys %prob_type ) {
	print LOG "$_ $prob_type{$_}\n";
}

Here is the output I am getting. (I threw some routers in the array above):

Code:
Problem Types and counts
server,critical 310960
pc,critical 2535


I was getting ready to create another foreach loop for the normal and warning tickets, and thought there may be a better way.

Thanks

I got a Biz Degree! How the h*ll did I get here?
 
food for thought:

Code:
my %devType = ();

foreach (@type_chart) {
    my ($typ,$cri) = split (/,/);
    $devType{$typ}{'WARNING'}++  if $cri eq 'warning';
    $devType{$typ}{'NORMAL'}++   if $cri eq 'normal';
    $devType{$typ}{'CRITICAL'}++ if $cri eq 'critical';
}

foreach my $typ (keys %devType) {
   print "$typ,$devType{$typ}{'CRITICAL'},$devType{$typ}{'WARNING'},$devType{$typ}{'NORMAL'}\n";
}
 
Along the same lines as KevinADC. (Using an HoH.)
Code:
#!perl
use strict;
use warnings;

my %h;
my @types = qw(critical warning normal);

while (<DATA>) {
    chomp;
    my ($thing, $type) = split /,/;
    $h{$thing}->{$type}++;
}

print join(", ", ('devTypes', @types)), "\n";
for my $k (sort keys %h) {
    # fill in zeros for undefined values
    @{$h{$k}}{@types} = map {defined($_)? $_: 0} @{$h{$k}}{@types};
    print join(", ", ($k, @{$h{$k}}{@types})), "\n";
}

# __DATA__ as posted above
Output:
Code:
devTypes, critical, warning, normal
pc, 0, 3, 18
router, 1, 0, 5
server, 9, 12, 120
 
Thanks Kevin and Mike. I already used Kevin's code in my script and I DO need to:

# fill in zeros for undefined values

How can I do that using Kevin's code?

Thanks,

Nick

I got a Biz Degree! How the h*ll did I get here?
 
Code:
[b]my @types = qw(CRITICAL WARNING NORMAL);[/b]

foreach my $typ (keys %devtype) {
    [b]# fill in zeros for undefined values
    @{$devtype{$typ}}{@types} = 
        map {defined($_)? $_: 0} 
        @{$devtype{$typ}}{@types};[/b]

    print "$typ,";
    print join(",", @{$devtype{$typ}}{@types}), "\n";
}


 
Note that you could declare @types earlier and use it while constructing %devtype;
Code:
my %devtype = ();
[b]my @types = qw(CRITICAL WARNING NORMAL);[/b]

foreach (@type_chart) {
    my ($typ, $cri) = split (/,/);
    [b]for (@types) {
        if (uc($cri) eq $_) {
            $devtype{$typ}->{$_}++;
            last;
        }
    }[/b]
}
 
Or, without using last:
Code:
my %devtype;
my @types = qw(CRITICAL WARNING NORMAL);
foreach (@type_chart) {
    my ($typ,$cri) = split (/,/);
    [b]for (my ($i,$found)=(0,0); $i<@types && !$found; $i++) {
        if ($found = (uc($cri) eq $types[$i])) {
            $devtype{$typ}->{$types[$i]}++;
        }
    }[/b]
}



 
Thanks for all the replies. The reason I was leaning to Kevin's code is because I understood what he was doing. I try not to use code I do not understand anymore. That being said, I see what you are doing Mike, excepts for this line:

Code:
@{$h{$k}}{@types} = map {defined($_)? $_: 0} @{$h{$k}}{@types};

I get this part:

@{$h{$k}}{@types}

but what is this part doing?
map {defined($_)? $_: 0} @{$h{$k}}{@types}


Also Mike. I put your code in my script as follows, but it does not seem to be generating the zero's. I had to modify the while loop.

Code:
	my %h;
	my @types = qw(critical warning normal);
	
	foreach (@type_chart) {
	    chomp;
	    my ($type, $cri) = split /,/;
	    $h{$cri}->{$type}++;
	}
	
	print LOG "Problem Types and counts\n\n";
	#print LOG "devType, critical, warning, normal\n";
	print join(", ", ('devTypes', @types)), "\n";
	for my $k (sort keys %h) {
	    # fill in zeros for undefined values
	    @{$h{$k}}{@types} = map {defined($_)? $_: 0} @{$h{$k}}{@types};
	    print LOG join(", ", ($k, @{$h{$k}}{@types})), "\n";
	}


ouput:

Code:
Problem Types and counts

devType, critical, warning, normal
network,323,20,
router,70,1,3

Thanks,

Nick

I got a Biz Degree! How the h*ll did I get here?
 
Mike,

Please disregard privious post. I am still testing.

I got a Biz Degree! How the h*ll did I get here?
 
Ok, with my code posted above:

Code:
	my %h;
	my @types = qw(critical warning normal);
	
	foreach (@type_chart) {
	    chomp;
	    my ($type, $cri) = split /,/;
	    $h{$cri}->{$type}++;
	}
	
	print LOG "Problem Types and counts\n\n";
	#print LOG "devType, critical, warning, normal\n";
	print LOG join(", ", ('devTypes', @types)), "\n";
	for my $k (sort keys %h) {
	    # fill in zeros for undefined values
	    @{$h{$k}}{@types} = map {defined($_)? $_: 0} @{$h{$k}}{@types};
	    print LOG join(", ", ($k, @{$h{$k}}{@types})), "\n";
	}

I am getting:

Code:
Problem Types and counts

devTypes, critical, warning, normal
critical, 0, 0, 0
normal, 0, 0, 0
warning, 0, 0, 0

Nick

I got a Biz Degree! How the h*ll did I get here?
 
Ok...I believe I got it. I just swapped the $cri and $type:

Code:
	my %h;
	my @types = qw(critical warning normal);
	
	foreach (@type_chart) {
	    chomp;
	    my ($cri, $type) = split /,/;
	    $h{$cri}->{$type}++;
	}
	
	print LOG "Problem Types and counts\n\n";
	#print LOG "devType, critical, warning, normal\n";
	print LOG join(", ", ('devTypes', @types)), "\n";
	for my $k (sort keys %h) {
	    # fill in zeros for undefined values
	    @{$h{$k}}{@types} = map {defined($_)? $_: 0} @{$h{$k}}{@types};
	    print LOG join(", ", ($k, @{$h{$k}}{@types})), "\n";
	}


gives me:

Code:
Problem Types and counts

devTypes, critical, warning, normal
network, 323, 20, 0
switch, 70, 1, 3

I would still like to know what the:

Code:
@{$h{$k}}{@types} = map {defined($_)? $_: 0} @{$h{$k}}{@types};

is doing. I will look up the map command.

NIck

I got a Biz Degree! How the h*ll did I get here?
 
Code:
    foreach (@type_chart) {
        chomp;
        [b]my ($type, $cri) = split /,/;
        $h{$cri}->{$type}++;[/b]
    }
If your data looks like what you posted above, the first field in the split is the key in the 'outer' hash, the second field is the key in the 'inner' hash. If you call the 2 fields $type and $cri (I don't 'get' the mnemonic significance of '$cri'), then the above is incorrect. It should be
Code:
    foreach (@type_chart) {
        chomp;
        [b]my ($type, $cri) = split /,/;
        $h{$type}->{$cri}++;[/b]
    }


 
Thanks Mike,

It does not seem to matter. This works:

Code:
            my ($type, $cri) = split /,/;
	    $h{$type}->{$cri}++;

and this works as well:

Code:
            my ($cri, $type) = split /,/;
            $h{$cri}->{$type}++;

Both give (not based on the above exact data, but the format is the same):

Code:
Problem Types and counts

devTypes, critical, warning, normal
network, 323, 20, 0
switch, 70, 1, 3

As far as the $cri variable. That is short for "criticality" which is really what the variable represents. Bottom line, this program is over 1000 lines now and I am running low on variable names.

Nick



I got a Biz Degree! How the h*ll did I get here?
 
I see you realized on your own that you switched the 2 fields in the split.

Besides not getting the mnemonic significance of '$cri,' I also don't think '$type' is a good name for the first field in the split, as the keys in the inner hash are in the array called @types, and the name similarity is liable to cause confusion. (And perhaps it has already?) I liked $thing and $type for the 2 fields in the split, but even if you don't use these, I still wouldn't call the first field $type, since it's a key in the outer hash.

Yes, look up the map function. Hint: the expression that uses map could also be written
Code:
@{$h{$k}}{@types} = [b]map {$_ eq undef? 0: $_}[/b] @{$h{$k}}{@types};



 
Thanks Mike,

Took your advice and now $type is $thing. Studying map. I see how this works:

my @words = map { s/[.,!\?]\B//g; split; } <FILE>;

map returns a list, so you will usually assign it to some type of array or hash. In this example map is a loop that runs two commands on <FILE> the substitution and the split. Very useful with some practice.


in your map:

@{$h{$k}}{@types} =

Just a reference to an array. I'm finally getting that.

map {defined($_)

Ok..map, run some commands and return a list to put in our array. Here there needs to be something in the default loop variable.

but this part I don't get:

? $_: 0 [3eyes] #HUH?????

and the last part:

@{$h{$k}}{@types}

just reading in the same array we are writtig to, effectively filtering it.

Nick

I got a Biz Degree! How the h*ll did I get here?
 
@{$h{$k}}{@types} =

Just a reference to an array. I'm finally getting that.
Nope, not a reference to an array, but an array. The array in this case is the values of the hash %{$h{$k}}.

For the ?: bit, see perldoc perlop and look for Conditional Operator. It's like an if-then-else, basically. The part before the ? is the condition, the part after the ? is the then branch, and the part after the : is the else branch. Very handy sometimes. (Though a little of this goes a long way.)

HTH

 
IC!

Code:
@{$h{$k}}{@types} = map {defined($_)? $_: 0} @{$h{$k}}{@types};

"if" defined($_) ? "then" map $_ to our array

"else" map a 0.

nice.

Nick

I got a Biz Degree! How the h*ll did I get here?
 
Another way to think of it:
Code:
for my $k (sort keys %h) {
    # fill in zeros for undefined values
    @{$h{$k}}{@types} = [b]mymap(\&undef2zero, @{$h{$k}}{@types});[/b]
    print "$k,", join(",", @{$h{$k}}{@types}), "\n";
}

[b]sub undef2zero {
    if (!defined($_[0])) {
        $_[0] = 0;
    }
    return $_[0];
}
sub mymap {
    my ($funcref, @list) = @_;
    for my $elem (@list) {
        $funcref->($elem);
    }
    return @list;
}[/b]

 
Actually, the return statement in undef2zero serves no purpose, since it modifies its argument "in place." So it should be
Code:
sub undef2zero {
    if (!defined($_[0])) {
        $_[0] = 0;
    }
}
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top