MrSpoocy: grep dont return a ref to match.

Hi,

here is a Simple example:

my $testdata = [{  
		'User'	=> [4545454,45354654,564656565],  
		'Amount'	=> 100,  
	},{  
		'User'	=> [2985454,4535345],  
		'Amount'	=> 187,  
	},{  
		'User'	=> [45,4654554],  
		'Amount'	=> 157,  
	},{  
		'User'	=> [2222],  
		'Amount'	=> 245,  
	},  
];  
  
my $tryToFind = 4654554;  

  
# Now i search for the entry, but i can not change :(  
if (grep {    grep {$_ eq $tryToFind}  @{$_->{'User'}}   } @{$testdata})  
{  
	$_->{'Amount'} = 158;  
	print "FOUND !";  
}  
print Dumper($testdata );  

  
# When i use this ... than work's  
foreach (grep { grep {$_ eq $tryToFind}  @{$_->{'User'}}  } @{$testdata})  
{  
	print "Got match " . $_->{"Amount"} . "\n";  
	$_->{"Amount"} = 158;  
}  
print Dumper($testdata );  

what is wrong with if ? If i found the User in the Array, than i need the ref to change the values from him. I will not copy the entry's

mfg Spoocy

  1. hi,

    Now i search for the entry, but i can not change :(

    if (grep {    grep {$_ eq $tryToFind}  @{$_->{'User'}}   } @{$testdata})

    This 'if'-control is always TRUE. Btw., using grep, consider meaning $_ in block{}.

    The better way, step by step, using two loops:

      
    # @{$testdata} is a list of hash-references, 1st loop:  
    foreach my $href (@{$testdata}){  
    	# each hash contains a list of numbers in attribute {User}  
    	# second loop:  
    	foreach my $user( @{$href->{User}}){  
    		if($user == $tryToFind){ # numeric comparison  
    			# now, we can change the value for {Amount}  
    			# direct access  
    			$href->{Amount} = 158;  
    		}  
    	}  
    }  
    
    

    Hotti

  2. Bei deinem schlechten Englisch stehen einem ja die Haare zu Berge. Du darfst ruhig weiterhin auf deutsch schreiben.

    Das Problem liegt daran, dass du wohl nicht siehst, dass der grep-Ausdruck in beiden Beispielen zuerst komplett ausgewertet wird (hottis Vermutung im Threadnachbar ist irreführend).

    Zu if:
    Das $_ im Block mit der Zuweisung ist dann ein komplett eigenständiges, also kein Alias für die Elemente aus den dereferenzierten Arrayreferenzen. Die Ausgabe von $_ nach der Anweisung zeigt dementsprechend auch nur

      
        {  
          'Amount' => 158  
        }  
    
    

    Zu foreach:
    foreach iteriert über die Liste und macht jeweils einen Alias für jedes Element. Der grep-Ausdruck liefert genau ein Listenelement. foreach dient als Topicaliser, daher ist das $_ der von dir erwartete Wert und der Funktionsweise des Codes deckt sich mit deinen Erwartungen. Noch einmal mit deutlicheren Worten: es geht, aber nur zufällig.

    Alles in allem sind beide Versionen sehr bizarrer Code. Siehe hottis Codebeispiel, wie man's richtig macht. Ich würde es so schreiben:

      
    my $testdata =;  
    for (@$testdata) {  
        $_->{Amount} = 158 if 4654554 ~~ $_->{User};  
    }