2016-12-31 6 views
-1

Ich habe Probleme mit dem Schreiben eines Perl-Skripts.Manipulieren und auf den Inhalt eines Hashes von Hashes zugreifen

Dies ist die Aufgabe:

question for perl script

Mein Code funktioniert gut, aber hat zwei Probleme.

  1. Ich möchte %grocery ein Element zu dem Hash hinzuzufügen, die Kategorie, Marke und Preis enthält. Wenn Sie den Artikel hinzufügen, fragt das System zuerst nach der Kategorie.

    Wenn die Kategorie nicht existiert, wird eine neue Kategorie, Marke und Preis vom Benutzer hinzugefügt, aber wenn die Kategorie bereits existiert, wird der Markenname und Preis vom Benutzer genommen und an die existierende Kategorie angehängt .

    Wenn ich versuche, löscht es die bereits vorhandenen Elemente. Ich möchte die vorherigen Elemente mit dem neu hinzugefügten Element angehängt haben.

  2. Dieses Problem tritt mit dem Maximalwert auf. Um den maximalen Preis in dem gegebenen Hash zu finden. Ich bekomme dafür einen Müllwert.

    Was mache ich falsch?

Hier ist mein vollständiger Code:

use strict; 
use warnings; 

use List::Util qw(max); 
use feature "switch"; 

my $b; 
my $c; 
my $p; 
my $highest; 

print "____________________________STORE THE ITEM_____________________\n"; 

my %grocery = (
    "soap"  => { "lux" => 13.00, "enriche" => 11.00 }, 
    "detergent" => { "surf" => 18.00 }, 
    "cleaner" => { "domex" => 75.00 } 
); 

foreach my $c (keys %grocery) { 
    print "\n"; 
    print "$c\n"; 
    foreach my $b (keys %{ $grocery{$c} }) { 
     print "$b:$grocery{$c}{$b}\n"; 
    } 
} 

my $ch; 

do { 
    print "________________MENU_________________\n"; 
    print "1.ADD ITEM\n"; 
    print "2.SEARCH\n"; 
    print "3.DISPLAY\n"; 
    print "4.FIND THE MAX PRICE\n"; 
    print "5.EXIT\n"; 
    print "enter your choice \n"; 
    $ch = <STDIN>; 
    chomp($ch); 

    given ($ch) { 

     when (1) { 
      print "Enter the category you want to add"; 
      $c = <STDIN>; 
      chomp($c); 

      if (exists($grocery{$c})) { 

       print "Enter brand\n"; 
       $b = <STDIN>; 
       chomp($b); 

       print "Enter price\n"; 
       $p = <STDIN>; 
       chomp($p); 

       $grocery{$c} = { $b, $p }; 

       print "\n"; 
      } 
      else { 

       print "Enter brand\n"; 
       $b = <STDIN>; 
       chomp($b); 

       print "Enter price\n"; 
       $p = <STDIN>; 
       chomp($p); 

       $grocery{$c} = { $b, $p }; 

       print "\n"; 
      } 
     } 

     when (2) { 

      print "Enter the item that you want to search\n"; 
      $c = <STDIN>; 
      chomp($c); 

      if (exists($grocery{$c})) { 

       print "category $c exists\n\n"; 
       print "Enter brand\n"; 
       $b = <STDIN>; 
       chomp($b); 

       if (exists($grocery{$c}{$b})) { 
        print "brand $b of category $c exists\n\n"; 
        print "-----$c-----\n"; 
        print "$b: $grocery{$c}{$b}\n"; 
       } 
       else { 
        print "brand $b does not exists\n"; 
       } 
      } 
      else { 
       print "category $c does not exists\n"; 
      } 
     } 

     when (3) { 

      foreach $c (keys %grocery) { 

       print "$c:\n"; 

       foreach $b (keys %{ $grocery{$c} }) { 
        print "$b:$grocery{$c}{$b}\n"; 
       } 
      } 
     } 

     when (4) { 

      print "\n________________PRINT HIGHEST PRICED PRODUCT____________________\n"; 
      $highest = max values %grocery; 
      print "$highest\n"; 
     } 
    } 

} while ($ch != 5); 
+0

Haben Sie gelernt, 'gegeben'/'wann' zu verwenden? Es ist eine * experimentelle * Funktion, daher kann sich ihre Funktion ändern oder in zukünftigen Versionen von Perl ganz verschwinden. Es ist am besten, es zu vermeiden. – Borodin

+0

Verwenden Sie keine single-character Variablennamen, es sei denn, sie sind etablierte wie $ i für einen Index oder $ s für eine generische Zeichenfolge. '$ a' und' $ b' sind reservierte Identifikatoren und sollten vollständig vermieden werden. – Borodin

+1

Sobald Sie mit Ihrer Aufgabe fertig sind, schlage ich vor, dass Sie es bei [codereview.se] veröffentlichen und wir sagen Ihnen, wie Sie es verbessern können. – simbabque

Antwort

4

Wenn ich versuche, dies zu tun es die bereits existierenden Elemente löscht. Ich möchte die vorherigen Elemente mit dem neu hinzugefügten Element angehängt haben.

In dieser Zeile überschreiben Sie den Wert $grocery{$c} mit einer neuen Hash-Referenz.

$grocery{$c}={$b,$p}; 

Stattdessen müssen Sie die vorhandene Hashreferenz bearbeiten.

$grocery{$c}->{$b} = $p; 

, dass ein neuer Schlüssel $b an die bestehende Datenstruktur innerhalb von $grocery{$b} und weisen Sie ihm den Wert von $p hinzufügen.

Werfen wir einen Blick darauf, was das bedeutet. Ich habe dies dem Code hinzugefügt, nachdem %grocery initialisiert wird.

use Data::Dumper; 
print Dumper \%grocery; 

Wir erhalten die folgende Ausgabe. Hashes werden nicht sortiert, daher kann die Reihenfolge für Sie unterschiedlich sein.

$VAR1 = { 
     'cleaner' => { 
        'domex' => '75' 
        }, 
     'detergent' => { 
         'surf' => '18' 
        }, 
     'soap' => { 
        'enriche' => '11', 
        'lux' => '13' 
       } 
    }; 

Wie Sie sehen können, haben wir Hashes innerhalb von Hashes. In Perl werden Referenzen verwendet, um eine mehrstufige Datenstruktur aufzubauen. Sie können das von den geschweiften Klammern {} in der Ausgabe sehen. Die allererste nach $VAR1 ist, weil ich eine Referenz von $grocery zu Dumper übergeben, indem Sie den Backslash \ vor.

Also hinter dem Wert für $grocery{"cleaner"} ist eine Hash-Referenz { "domex" => 75 }. Um in diese Hash-Referenz zu gelangen, müssen Sie den Dereferenzierungsoperator -> verwenden. Sie können dann einen neuen Schlüssel in diesen Hash-Ref eingeben, wie ich oben gezeigt habe.

#     ##!!!!!!!!!! 
$grocery{"cleaner"}->{"foobar"} = 30; 

Ich habe die relevanten Teile oben mit einem Kommentar markiert. Sie können in den folgenden Dokumenten nachlesen: perlreftut, perllol, perldsc und perlref.


Dieses Problem ist mit dem Maximalwert. Um das Maximum der Werte des gegebenen Hash zu finden. Ich bekomme dafür einen Müllwert.

Dieses Problem basiert auch auf der Tatsache, dass Sie Referenzen noch nicht verstehen.

$highest = max values %grocery; 

Ihr Code wird nehmen nur die direkt Werte innerhalb %grocery. Wenn Sie nach oben scrollen und die Dumper-Ausgabe erneut betrachten, sehen Sie, dass es drei Hash-Referenzen innerhalb von %grocery gibt. Jetzt, wenn Sie sie nicht dereferenzieren, erhalten Sie nur ihre skalare Darstellung. Ein Skalar in Perl ist ein einzelner Wert, z. B. eine Zahl oder eine Zeichenfolge. Aber für Referenzen ist es deren Typ und Adresse. Was wie Müll aussieht, ist tatsächlich die Speicheradresse der drei Hash-Referenzen in %grocery, die die höchste Nummer hat.

Natürlich ist das nicht das, was Sie wollen. Sie müssen beide Ebenen Ihrer Datenstruktur durchlaufen, alle Werte sammeln und dann die höchste finden.

my @all_prices; 
foreach my $category (keys %grocery) { 
    push @all_prices, values %{ $grocery{$category} }; 
} 
$highest = max @all_prices; 
print "$highest\n"; 

Ich wählte einen sehr ausführlichen Ansatz, um das zu tun. Es iteriert über alle Kategorien in %grocery und ergreift dann alle values der Hash-Referenz hinter jedem von ihnen gespeichert. Diese werden zu einem Array hinzugefügt, und am Ende können wir die max von allen aus dem Array nehmen.

+0

und wie die Kategorie und Markendetails mit dem höchsten Preis – ayav

+0

angezeigt werden und wie die Kategorie und Markeninformationen mit dem höchsten Preis @simbabque – ayav

+0

@ayav anzeigen, das ist schwieriger. Sie müssen das Maximum selbst herausfinden und sich an den Rest der Daten erinnern. Ihnen zu sagen, wie Sie das tun, wird Ihnen nicht helfen zu lernen. – simbabque

2

Sie haben genau den gleichen Code für die, wenn eine Kategorie bereits existiert und wenn nicht. Die Linie

$grocery{$c} = { $b, $p }; 

ersetzt die gesamte Hash für Kategorie $c.Das ist für neue Kategorien in Ordnung, aber wenn die Kategorie bereits vorhanden ist, dann wird es alle vorhandenen Informationen

Sie benötigen

$grocery{$c}{$b} = $p; 

schreiben wegzuwerfen Und bitte ein viel mehr Leerzeichen um Operatoren hinzufügen, die Trenn Elemente der Listen und delineating verwandte Sequenzen von Anweisungen



Im Hinblick auf den maximalen Preis zu finden, Ihre Linie

$highest = max values %grocery; 

versucht, das Maximum der Hashreferenzen zu berechnen zu den Kategorien entsprechenden

Da es hier zwei Ebenen von Hash sind, was Sie brauchen

$highest = max map { values %$_ } values %grocery; 

aber das ist vielleicht nicht die Art und Weise, die Sie erwartet haben, es zu tun. Im Zweifelsfall sollten Sie dann zwei verschachtelte for Schleifen verwenden

-3
use List::Util qw(max); 
use Data::Dumper; 

my $grocery = 
{ 
    "soap"  => { "lux" => 13.00, "enriche" => 11.00 }, 
    "detergent" => { "surf" => 18.00 }, 
    "cleaner" => { "domex"=> 75.00 } 
}; 

display("unadulterated list"); 
print Dumper $grocery; 

display("new silky soap"); 
$grocery->{"soap"}->{"silky"} = 12.50; 
print Dumper $grocery; 

display("new mega cleaner"); 
$grocery->{"cleaner"}->{"megaclean"} = 99.99; 
print Dumper $grocery; 

display("new exfoliant soap"); 
$grocery->{"soap"}->{"exfoliant"} = 23.75; 
print Dumper $grocery; 

display("lux soap gets discounted"); 
$grocery->{"soap"}->{"lux"} = 9.00; 
print Dumper $grocery; 

display("domex cleaner is discontinued"); 
delete $grocery->{"cleaner"}->{"domex"}; 
print Dumper $grocery; 

display("most costly soap product"); 
my $max = max values $grocery->{soap}; 
print $max, "\n\n"; 

sub display 
{ 
    printf("\n%s\n%s\n%s\n\n", '-' x 45, shift, '-' x 45); 
} 
+3

Wie ist das hilfreich? Bitte erläutern Sie Ihren Code und warum er Ihrer Meinung nach die Frage beantwortet. – simbabque