Ποιος είναι ο ασφαλέστερος τρόπος για να μετακινηθείτε μέσα από τα πλήκτρα του κατακερματισμού Perl;

ψήφοι
84

Αν έχω ένα hash Perl με ένα μάτσο (κλειδί, τιμή) ζεύγη, ποια είναι η προτιμώμενη μέθοδος επανάληψη σε όλα τα κλειδιά; Έχω ακούσει ότι η χρήση eachμπορεί με κάποιο τρόπο να έχουν απρόβλεπτες παρενέργειες. Έτσι, είναι αλήθεια, και είναι μία από τις δύο ακόλουθες μεθόδους καλύτερα, ή είναι ένας καλύτερος τρόπος;

# Method 1
while (my ($key, $value) = each(%hash)) {
    # Something
}

# Method 2
foreach my $key (keys(%hash)) {
    # Something
}
Δημοσιεύθηκε 06/08/2008 στις 03:53
πηγή χρήστη
Σε άλλες γλώσσες...                            


9 απαντήσεις

ψήφοι
170

Ο γενικός κανόνας είναι να χρησιμοποιήσετε τη λειτουργία πιο κατάλληλη για τις ανάγκες σας.

Αν θέλετε μόνο τα κλειδιά και δεν σκοπεύουν να ποτέ να διαβάσει οποιαδήποτε από τις τιμές, χρησιμοποιήστε τα πλήκτρα ():

foreach my $key (keys %hash) { ... }

Αν θέλετε μόνο τις τιμές, χρησιμοποιήστε τις τιμές ():

foreach my $val (values %hash) { ... }

Αν χρειάζεστε τα κλειδιά και τις τιμές, χρησιμοποιήστε το καθένα ():

keys %hash; # reset the internal iterator so a prior each() doesn't affect the loop
while(my($k, $v) = each %hash) { ... }

Αν σκοπεύετε να αλλάξετε τα κλειδιά του κατακερματισμού με οποιονδήποτε τρόπο , εκτός για τη διαγραφή του τρέχοντος κλειδιού κατά τη διάρκεια της επανάληψης, τότε δεν πρέπει να χρησιμοποιήσετε το καθένα (). Για παράδειγμα, αυτός ο κώδικας για να δημιουργήσετε ένα νέο σύνολο των κεφαλαίων κλειδιών με διπλασιαστεί τιμές δουλεύει μια χαρά με τα πλήκτρα ():

%h = (a => 1, b => 2);

foreach my $k (keys %h)
{
  $h{uc $k} = $h{$k} * 2;
}

που παράγουν το αναμενόμενο προκύπτον hash:

(a => 1, A => 2, b => 2, B => 4)

Αλλά χρησιμοποιώντας κάθε () για να κάνουν το ίδιο πράγμα:

%h = (a => 1, b => 2);

keys %h;
while(my($k, $v) = each %h)
{
  $h{uc $k} = $h{$k} * 2; # BAD IDEA!
}

παράγει ανακριβή αποτελέσματα είναι δύσκολο να προβλέψει τρόπους. Για παράδειγμα:

(a => 1, A => 2, b => 2, B => 8)

Αυτό, όμως, είναι ασφαλές:

keys %h;
while(my($k, $v) = each %h)
{
  if(...)
  {
    delete $h{$k}; # This is safe
  }
}

Όλα αυτά που περιγράφονται στην τεκμηρίωση perl:

% perldoc -f keys
% perldoc -f each
Απαντήθηκε 06/08/2008 στις 14:22
πηγή χρήστη

ψήφοι
21

Ένα πράγμα που πρέπει να γνωρίζετε όταν χρησιμοποιούν eachείναι ότι έχει την παρενέργεια της προσθήκης «κατάσταση» για να hash σας (το hash έχει να θυμάται ποια είναι η «επόμενη» κλειδί). Όταν χρησιμοποιείτε κώδικα όπως τα αποσπάσματα δημοσιεύτηκε παραπάνω, η οποία επαναλάβει σε όλο το χασίς με μία κίνηση, αυτό δεν είναι συνήθως ένα πρόβλημα. Ωστόσο, θα τρέξει σε δύσκολο να εντοπίσουμε τα προβλήματα (μιλάω εκ πείρας?), Όταν χρησιμοποιείται eachσε συνδυασμό με δηλώσεις του τύπου lastή returnγια έξοδο από το while ... eachβρόχο, πριν να έχουν επεξεργαστεί όλα τα κλειδιά.

Σε αυτή την περίπτωση, το κλειδί κατακερματισμού θα θυμάται ποια πλήκτρα έχει ήδη επιστρέψει, και όταν χρησιμοποιείτε eachσε αυτό την επόμενη φορά που (ίσως σε μια ολοκληρωτικά άσχετες κομμάτι του κώδικα), θα συνεχίσει σε αυτή τη θέση.

Παράδειγμα:

my %hash = ( foo => 1, bar => 2, baz => 3, quux => 4 );

# find key 'baz'
while ( my ($k, $v) = each %hash ) {
    print "found key $k\n";
    last if $k eq 'baz'; # found it!
}

# later ...

print "the hash contains:\n";

# iterate over all keys:
while ( my ($k, $v) = each %hash ) {
    print "$k => $v\n";
}

Αυτή εκτυπώσεις:

found key bar
found key baz
the hash contains:
quux => 4
foo => 1

Τι συνέβη με τα πλήκτρα «bar» και baz "; Είναι ακόμα εκεί, αλλά η δεύτερη eachξεκινά όταν η πρώτη που σταμάτησε, και σταματά όταν φτάσει στο τέλος του κατακερματισμού, γι 'αυτό ποτέ δεν τους βλέπω στο δεύτερο loop.

Απαντήθηκε 16/09/2008 στις 00:37
πηγή χρήστη

ψήφοι
19

Το μέρος όπου eachμπορεί να προκαλέσει προβλήματα σας είναι ότι είναι μια πραγματική, μη με εύρος iterator. Ως παράδειγμα:

while ( my ($key,$val) = each %a_hash ) {
    print "$key => $val\n";
    last if $val; #exits loop when $val is true
}

# but "each" hasn't reset!!
while ( my ($key,$val) = each %a_hash ) {
    # continues where the last loop left off
    print "$key => $val\n";
}

Εάν πρέπει να είστε βέβαιοι ότι eachπαίρνει όλα τα πλήκτρα και τις αξίες, θα πρέπει να βεβαιωθείτε ότι έχετε χρησιμοποιήσει keysή valuesπρώτη (όπως η επαναφορά του iterator). Δείτε την τεκμηρίωση για κάθε έναν .

Απαντήθηκε 16/09/2008 στις 15:35
πηγή χρήστη

ψήφοι
13

Χρησιμοποιώντας το κάθε σύνταξη θα εμποδίσει ολόκληρο το σύνολο των πλήκτρων κατά δημιουργούνται ταυτόχρονα. Αυτό μπορεί να είναι σημαντικό εάν χρησιμοποιείτε ένα hash γραβάτα-ed σε μια βάση δεδομένων με εκατομμύρια γραμμές. Δεν θέλετε να δημιουργήσετε ολόκληρη τη λίστα των κλειδιών όλα με τη μία και να εξαντλήσει φυσική μνήμη σας. Στην περίπτωση αυτή κάθε χρησιμεύει ως ένας iterator ενώ τα πλήκτρα παράγει πράγματι το σύνολο της συστοιχίας πριν αρχίσει ο βρόχος.

Έτσι, το μόνο μέρος «κάθε» είναι πραγματική χρήση είναι όταν το hash είναι πολύ μεγάλη (σε σχέση με την διαθέσιμη μνήμη). Αυτό είναι πιθανό να συμβεί, όταν το ίδιο το hash δεν ζουν στη μνήμη ίδια εκτός αν τον προγραμματισμό μια φορητή συσκευή συλλογής δεδομένων ή κάτι με μικρή μνήμη μόνο.

Αν η μνήμη δεν είναι ένα θέμα, συνήθως το πρότυπο χάρτη ή τα πλήκτρα είναι η πιο διαδεδομένη και πιο εύκολο να διαβάσει παράδειγμα.

Απαντήθηκε 11/09/2008 στις 23:04
πηγή χρήστη

ψήφοι
5

Λίγα διάφορες σκέψεις για το θέμα αυτό:

  1. Δεν υπάρχει τίποτα μη ασφαλή για οποιοδήποτε από τους ίδιους τους επαναλήπτες hash. Τι είναι μη ασφαλές αποτελεί τροποποίηση των κλειδιών του κατακερματισμού, ενώ είστε επανάληψη πάνω του. (Είναι απόλυτα ασφαλές να τροποποιήσει τις τιμές.) Το μόνο πιθανό παρενέργεια που μπορώ να σκεφτώ είναι ότι valuesεπιστρέφει ψευδώνυμα που σημαίνει ότι τροποποιώντας τους θα τροποποιήσει τα περιεχόμενα του hash. Αυτό οφείλεται στη σχεδίαση, αλλά μπορεί να μην είναι ό, τι θέλετε σε ορισμένες περιπτώσεις.
  2. Ιωάννη αποδεκτή απάντηση είναι καλή, με μία εξαίρεση: η τεκμηρίωση είναι σαφές ότι δεν είναι ασφαλές να προσθέσετε τα πλήκτρα ενώ επανάληψη πάνω από ένα hash. Μπορεί να λειτουργήσει για μερικούς σύνολα δεδομένων, αλλά θα αποτύχει για τους άλλους, ανάλογα με τη σειρά hash.
  3. Όπως έχει ήδη αναφερθεί, είναι ασφαλές να διαγράψετε το τελευταίο κλειδί επέστρεψε από each. Αυτό είναι που δεν ισχύει για keysόσο eachείναι ένας iterator, ενώ keysεπιστρέφει μια λίστα.
Απαντήθηκε 15/09/2008 στις 22:36
πηγή χρήστη

ψήφοι
4

Χρησιμοποιώ πάντα τη μέθοδο 2, καθώς και. Το μόνο όφελος από τη χρήση κάθε είναι αν είστε απλά διαβάζοντας (και όχι την εκ νέου ανάθεση) την τιμή της καταχώρησης hash, δεν είστε συνεχώς de-αναφορά του κατακερματισμού.

Απαντήθηκε 06/08/2008 στις 05:04
πηγή χρήστη

ψήφοι
4

Αυτό μπορεί να πάρει τσίμπημα από αυτό, αλλά νομίζω ότι είναι προσωπική προτίμηση. Δεν μπορώ να βρω καμία αναφορά στα έγγραφα σε κάθε () είναι διαφορετική από ό, τι τα κλειδιά () ή τιμές () (εκτός από το προφανές «επιστρέφουν διαφορετικά πράγματα» απάντηση. Στην πραγματικότητα, τα έγγραφα αναφέρουν την χρήση του ίδιου iterator και όλοι επιστρέφουν πραγματικές τιμές καταλόγου, αντί των αντιγράφων τους, και ότι η τροποποίηση του κατακερματισμού, ενώ επανάληψη πάνω από το χρησιμοποιούν οποιαδήποτε κλήση είναι κακό.

Όλα αυτά που είπε, χρησιμοποιώ σχεδόν πάντα τα κλειδιά (), γιατί για μένα είναι συνήθως πιο αυτο τεκμηρίωση για να αποκτήσετε πρόσβαση αξία του κλειδιού μέσω της ίδιας της hash. Έχω κατά καιρούς χρησιμοποιήσει τιμές (), όταν η τιμή είναι μια αναφορά σε μια μεγάλη δομή και το κλειδί για την κατακερματισμού ήδη αποθηκευτεί στη δομή, οπότε το κλειδί είναι περιττή και δεν το χρειάζονται. Νομίζω ότι έχω χρησιμοποιήσει το καθένα () 2 φορές σε 10 χρόνια προγραμματισμού Perl και ήταν ίσως η λανθασμένη επιλογή δύο φορές =)

Απαντήθηκε 06/08/2008 στις 04:43
πηγή χρήστη

ψήφοι
1

Συνήθως χρησιμοποιώ keysκαι δεν μπορώ να σκεφτώ την τελευταία φορά που χρησιμοποιήθηκε ή να διαβάσει μια χρήση του each.

Μην ξεχάσουμε map, ανάλογα με το τι κάνετε στο βρόχο!

map { print "$_ => $hash{$_}\n" } keys %hash;
Απαντήθηκε 22/08/2008 στις 16:31
πηγή χρήστη

ψήφοι
-2

Θα woudl λένε:

  1. Χρησιμοποιήστε ό, τι είναι πιο εύκολο να διαβάσει / καταλάβει για τους περισσότερους ανθρώπους (τόσο κλειδιά, συνήθως, θα ήθελα να υποστηρίζουν)
  2. Χρησιμοποιήστε ό, τι αποφασίσει με συνέπεια μέσα από το σύνολο της βάσης κώδικα.

Αυτή δώσει 2 μεγάλα πλεονεκτήματα:

  1. Είναι πιο εύκολο να εντοπιστούν «κοινή» κώδικα, έτσι ώστε να μπορεί εκ νέου παράγοντα σε λειτουργίες / methiods.
  2. Είναι πιο εύκολο για τις μελλοντικές προγραμματιστές να διατηρηθεί.

Δεν νομίζω ότι είναι πιο ακριβά για να χρησιμοποιήσετε τα πλήκτρα πάνω από το καθένα, οπότε δεν υπάρχει ανάγκη για δύο διαφορετικές δομές για το ίδιο πράγμα με τον κωδικό σας.

Απαντήθηκε 20/12/2010 στις 13:46
πηγή χρήστη

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more