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 strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Help! Hash of arries can only hold done value per key 1

Status
Not open for further replies.

blues77

Programmer
Jun 11, 2002
230
CA
Can anyone tell me from looking at the code below why I'm only able to have one value per key in the hash despite using a hash of arrys. Below is my code. Any suggestions are appreciated. It seems from what I can tell that the code doesn't enter the part
Code:
 elsif (exists $hash{$2})
                		{
		                    print "We're adding a second value.  Examining with $line1\n";
                		    push @{ $hash{$2} }, $3;
		                }
when it encounters a key that exists but doesn't have the particular value being examined stored in it. Once one value is stored in that slot of the key then all subsequent values that happen to fall under that key are caught by the code

Code:
if (exists $hash{$2}[$3] ) 
		                {
                		    print "key value pair already exists for elemetn $line1\n";
		                    #do nothing
                		}
which won't add the key then of course. But this should not be happening since the value in question (i.e. $2) has not been added yet. Only the key is present with another value currently being sotred there. Thanks for your help.


Code:
#use strict;

#print "$ARGV[0]";
open(MY_FILE1,$ARGV[0]); 
open(OUTPUT, ">>output.txt");

while(<MY_FILE1>)
{
	chomp;
	my $line1 = $_;
	my %hash = ();
	my $flag = 0;
	my $view = 0;
	my $noCAASsource = 0;

	open(MY_FILE2,$ARGV[1]);
	while(<MY_FILE2>)
	{	
		chomp;
		my $line2 = $_;

		if($line2 =~ /^\s*$/)
		{
			#do nothing
		}
		elsif($line2 =~ /^($line1)\s+/)
		{
			if($line2 =~ /^($line1)\s+CAAS.+\.([^.]+)\.([^.]+)/ )
			{
				$flag = 1;

				if (exists $hash{$2}[$3] ) 
		                {
                		    print "key value pair already exists for elemetn $line1\n";
		                    #do nothing
                		}
		                elsif (exists $hash{$2})
                		{
		                    print "We're adding a second value.  Examining with $line1\n";
                		    push @{ $hash{$2} }, $3;
		                }
		                else
                		{
		                    print "We're adding a brand new key\n";
                		    $hash{$2} = $3;
		                }	
			}
			if($line2 =~/^($line1)\s+View/)
			{
				$view = 1;
			}
			if($line2 =~/^($line1)\s+NO CAAS Source/)
			{
				$noCAASsource = 1;
			}
		}
		
	}
	if($flag == 0 && $view == 0 && $noCAASsource == 0)
	{
		print "nothing found\n";
		print OUTPUT "nothing found\n";
	}
	elsif($flag == 0 && $view == 1)
	{
		print "view\n";
	}
	elsif($flag == 0 && $view == 0 && $noCAASsource == 1)
	{
		print "NO CAAS Source\n"
	}
	elsif($flag == 1 && $view == 0)
	{
		print keys %hash, ;
		print "\n";
	}
	elsif($flag == 1 && $view == 1)
	{	
		foreach (keys %hash) 
		{
			#remove all whitespace using search and replace
			$_ =~ s/ //g;
			chomp;
			print OUTPUT "$_,";
		}
		
		print OUTPUT "\t";

		foreach (keys %hash)
		{
			my $key = $_;
			foreach (0 .. @{ $hash{$key} } - 1) 
			{
				my $n = $hash{$key}[$_];
				$n =~ s/ //g;
				print OUTPUT $n . ", ";
			}
		}
		
		print OUTPUT "\n";
		
		print "View $line1 has a segment and COBOL field\n";
	}

	$noCAASsource = 0;
	$flag = 0;
	$view = 0;
	close MY_FILE2;
}

close OUTPUT;
close MY_FILE1;
close MY_FILE2;
 
this is wrong:

if (exists $hash{$2}[$3] )

are you trying to see if $3 already exists in the array? You can't do it that way, you have to dereference the array and check for the value in a loop:

Code:
for (@{ $hash{$2} }) {
   print "exists in the array" if $3 eq $_;
}
 
That's exactly what I'm trying to do. I tried your suggestion but I'm stillonly getting one value per key/value pair in the hash. Once the ky in the hash has a value stored any subsequent value with the same key designation will not be entered into the hash becuase i think it's being caught by the statement

Code:
	#if (exists $hash{$2} && defined $hash{$2} )
				#{
				#   print "We're adding to an existing key/value pair\n";
				#   push @{$hash{$2} },  $3;
				#}
				#else
				#{
				#   print "We're adding a new key/value pair.  Examining with $line1\n";
				#   push @{ $hash{$2} }, $3;
				#}

				if (exists $hash{$2}) 
				{
				   for (@{ $hash{$2} }) 
				   {
				   	   print "exists in the array" if $3 eq $_;
				   } 
		                    #do nothing
				}
				elsif (exists $hash{$2})
			        {
				    print "We're adding a second value.  Examining with $line1\n";
				    push @{ $hash{$2} }, $3;
				}
				else
				{
				    print "We're adding a brand new key\n";
				    push @{$hash{$2}}, $3;
				}

I tried your other suggestion (it's commented out in the code above) and it did allow multiple values to be entered in for a key but the values were repeating. I want distict values for each key.

Any thoughts??

 
I'm thinking you might really want to use a hash of hashes if you want uniqueness throughout the data. But you can loop through the array like I showed you above to check for an existing value in the array. Maybe like this:

Code:
if (exists $hash{$2} && defined $hash{$2} ){
   print "Checking if value exists in the array\n:"
   my $flag = 0;
   for (@{ $hash{$2} }) {
      if ($3 eq $_) {$flag = 1;last;}
   }
   if ($flag) {
      print "Adding value to the array\n:";
      push @{ $hash{$2} },$3;
   }
   else {
      print "Value already exists in the array:\n"
   }
}
elsif (....)
else {...}
 
if you don't need all that sanity checking you could reduce the code to:

Code:
if (exists $hash{$2} && defined $hash{$2} ){
   $3 eq $_ ? push @{ $hash{$2} },$3 : last for (@{ $hash{$2} });
}
elsif (...) {
 ...
}
else {
 ...
}
 
It's working perfect now. Thanks to all of youu for all your help. Here is the final code. Feel free to make any suggestions on how to make things more efficient.

Thank you!

Code:
#use strict;

#print "$ARGV[0]";
open(MY_FILE1,$ARGV[0]); 
open(OUTPUT, ">>output.txt");

while(<MY_FILE1>)
{
	chomp;
	my $line1 = $_;
	my %hash = ();
	my $flag = 0;
	my $view = 0;
	my $noCAASsource = 0;

	open(MY_FILE2,$ARGV[1]);
	while(<MY_FILE2>)
	{	
		chomp;
		my $line2 = $_;

		if($line2 =~ /^\s*$/)
		{
			#do nothing
		}
		elsif($line2 =~ /^($line1)\s+/)
		{
			if($line2 =~ /^($line1)\s+CAAS.+\.([^.]+)\.([^.]+)/ )
			{
				$flag = 1;
				
				if (exists $hash{$2}) 
				{
				   my $kpExists = 0;
				   for (@{ $hash{$2} }) 
				   {	 
					   if ($3 eq $_)
					   {
						   $kpExists = 1;
						   last;
					   }
				   } 

				   if ($kpExists == 1)
				   {
		                    	#do nothing
				   }
				   elsif ($kpExists == 0)
				   {
					  push @{ $hash{$2} }, $3; 
				   }
				   
				}
				
				else
				{
				    push @{$hash{$2}}, $3;
				}	
			}
			if($line2 =~/^($line1)\s+View/)
			{
				$view = 1;
			}
			if($line2 =~/^($line1)\s+NO CAAS Source/)
			{
				$noCAASsource = 1;
			}
		}
		
	}
	if($flag == 0 && $view == 0 && $noCAASsource == 0)
	{
		print "nothing found\n";
		print OUTPUT "nothing found\n";
	}
	elsif($flag == 0 && $view == 1)
	{
		print "view\n";
	}
	elsif($flag == 0 && $view == 0 && $noCAASsource == 1)
	{
		print "NO CAAS Source\n"
	}
	elsif($flag == 1 && $view == 0)
	{
		print keys %hash, ;
		print "\n";
	}
	elsif($flag == 1 && $view == 1)
	{	
		foreach (keys %hash) 
		{
			#remove all whitespace using search and replace
			$_ =~ s/ //g;
			chomp;
			print OUTPUT "$_,";
		}
		
		print OUTPUT "\t";

		foreach (keys %hash)
		{
			my $key = $_;
			foreach (0 .. @{ $hash{$key} } - 1) 
			{
				my $n = $hash{$key}[$_];
				$n =~ s/ //g;
				print OUTPUT $n . ", ";
			}
		}
		
		print OUTPUT "\n";
		
	}

	$noCAASsource = 0;
	$flag = 0;
	$view = 0;
	close MY_FILE2;
}

close OUTPUT;
close MY_FILE1;
close MY_FILE2;
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top