11
votes

Pourquoi devrais-je retourner un hash ou une référence de hachage à Perl?

Quel est le moyen le plus efficace d'accomplir ci-dessous? (Je sais qu'ils accomplissent la même chose, mais comment la plupart des gens feraient-ils cela entre les trois, et pourquoi em>?)

fichier A.pl h3> xxx pré>

Fichier B.PL H3>
my %hash = %{build_hash()};
# Do stuff with hash using $hash{$key}
# It is better, because now we don't have to dereference our hashref each time using ->?

sub build_hash
{
    # Build some hash
    my %hash = ();
    my @k = qw(hi bi no th xc ul 8e r);
    for ( @k )
    {
        $hash{$k} = 1;
    }

    return \%hash;
}


3 commentaires

Voir la question associée à la question perl retourne des fonctions, meilleures pratiques (il apparaît dans la liste associée à droite de cette page ...).


@DaoToad: Ne vous inquiétez pas sur le retour du contexte scalaire d'une fonction qui n'a aucun sens à appeler dans le contexte scalaire


Nous couvrons beaucoup de cela dans Perl intermédiaire ( Oreilly.com/catalog/9780596102067 ).


8 Réponses :


8
votes

Je retournerais la référence pour enregistrer le temps de traitement de l'aplatissement du hachage dans une liste de scalaires, construire le nouveau hachage et (éventuellement) déchets collectant le hachage local dans le sous-programme.


0 commentaires

5
votes

Ce que vous cherchez est un tranche de hachage em>: xxx pré>

L'opérateur x code> est décrit à Perldoc Perlop . P>

Voir Perldoc Perldsc et Perldoc Perlrefut A > Pour les tutoriels sur les structures de données et les références (les deux incontournables des débutants et des experts). Les tranches de hachage elles-mêmes sont mentionnées dans Perldoc Perldata . P>

En ce qui concerne le retour d'un hachage À partir d'une fonction, nous devriez normalement retourner le hachage lui-même, pas une référence. Vous pouvez utiliser une référence si le hachage est énorme em> et que la mémoire ou le temps est une préoccupation, mais cela ne devrait pas être votre préoccupation de préoccupation - obtenir le code de travail est. P>

retour Les valeurs des fonctions sont toujours des listes (où le retour d'un scalaire est essentiellement une liste d'un élément). Les hachages sont des listes de Perl: vous pouvez attribuer une autre à l'autre interchangeable (en supposant que la liste a un nombre pair d'éléments et il n'y a pas de collisions clés qui entraîneraient des valeurs perdues pendant la conversion): P>

$VAR1 = [
          'key1',
          'value1',
          'key2',
          'value2'
        ];

$VAR1 = {
          'key2' => 'value2',
          'key1' => 'value1'
        };


1 commentaires

Dans le codeBase, je travaille actuellement avec cela, ce serait une fonction simple appelée hashof exporté par le projetNamespace :: DataManip Fonction et approximativement implémenté comme Sub Hashof {Retourte {$ _ => 1} @_;} (avec un prototype de sucre et similaires). Notre hash_slice_of ($ hashref, @list) d'autre part chaque paire de la valeur de clé qui existe en $ hashref où la clé est également dans @List. En tant que fonction de manipulation de hachage, ils renvoient tous les hachages (listes de taille même) afin que les valeurs de retour soient plus faciles à utiliser et à passer les unes aux autres.



1
votes

Prenez un soin: a.pl renvoie une liste avec un nombre pair d'éléments, pas un hash. Lorsque vous attribuez ensuite une telle liste à une variable de hachage, le hachage sera construit avec les éléments aux indices même en tant que touches et éléments des indices impairs en tant que valeurs. [EDIT: C'était comme ça que j'ai toujours vu la matière, mais Sub {...% hachage} se comporte un peu différemment de sous {... @List} . ]

Pour la même raison, la construction d'un hachage, la façon dont vous décrivez est aussi simple que: xxx

ma règle de base personnelle est d'éviter les références à moins que je ne fais pas besoin d'eux (par exemple, des structures imbriquées ou lorsque vous avez vraiment besoin de transmettre une référence à la même chose ).

EDIT: (Je ne peux pas cliquer sur "Ajouter un commentaire" link plus ?! Utilisation de la souris ici ...) J'y ai pensé un peu et je pense que passer autour de Hash Refs est probablement meilleur après tout, grâce à la façon dont nous utilisons un hash. Le paragraphe ci-dessus est toujours tenu pour le tableau Refs.

Merci pour vos commentaires Schwern et éther.


1 commentaires

+1 à l'utilisation de la carte pour créer un hachage d'une liste, -1 à l'idée d'éviter les références.



2
votes

a.pl et c.pl nécessite une copie du hachage à prendre (et le hachage interne à la fonction est marqué comme mémoire libre). b.pl , d'autre part, construit le hachage une seule fois et nécessite peu de mémoire supplémentaire pour renvoyer une référence sur laquelle vous pouvez utiliser. Ainsi, b.pl est plus susceptible d'être la forme la plus efficace des trois, à la fois dans l'espace et dans le temps.


0 commentaires

22
votes

Je préfère retourner un hachage Ref pour deux raisons. Un, il utilise un peu moins de mémoire car il n'y a pas de copie. Deux, il vous permet de le faire si vous avez juste besoin d'un morceau de hachage. XXX

Apprenez à aimer les références de hachage, vous allez les voir beaucoup une fois que vous avez commencé à utiliser des objets.


1 commentaires

Voulez-vous des œufs avec ça? (une référence de hachage implicite :)



2
votes

Je vais aller contre le grain et ce que tout le monde dit, et disons que je préfère que mes données sont revenues en tant que hachage (bien, en tant que liste de taille même susceptible d'être interprétée comme un hachage ). Je travaille dans un environnement où nous avons tendance à faire des choses comme l'extrait de code suivant, et il est beaucoup plus facile de combiner et de trier et de trancher et de couper des morts lorsque vous n'avez pas à Dréérence toutes les autres lignes. (Il est également agréable de savoir que quelqu'un ne peut pas endommager votre hashref parce que vous avez passé la valeur tout en valeur. EDIT: STRUT> Sauf si vous avez des références à d'autres objets / hachages / tableaux dans les valeurs de hachage. , alors vous êtes en difficulté quand même).

my %filtered_config_slice = 
   hashgrep { $a !~ /^apparent_/ && defined $b } (
   map { $_->build_config_slice(%some_params, some_other => 'param') } 
   ($self->partial_config_strategies, $other_config_strategy)
);


1 commentaires

Le problème est l'utilisation de la mémoire, pas nécessairement la vitesse. Lorsque vous êtes cavalier avec une utilisation de la mémoire, l'empreinte de votre application a tendance à exploser. Voir la réponse de Schwern.



9
votes

Pourquoi ne pas renvoyer les deux? Le contexte est une fonctionnalité très puissante de Perl pour permettre à vos fonctions de "faire ce que tu veux dire". Souvent, la décision est une meilleure valeur de rendement dépend de la manière dont le code d'appel prévoit utiliser la valeur, ce qui est exactement pourquoi Perl a le WANTLARRAY code>.

sub build_hash {
    my %hash;
    @hash{@keys} = (1) x @keys;
    wantarray ? %hash : \%hash
}

my %hash = build_hash;  # list context, a list of (key => value) pairs
my $href = build_hash;  # scalar context, a hash reference


3 commentaires

mon ($ href) = build_hash (); # whoops un peu trop d'aide pour pas assez de victoire.


@Schwern => Si une personne travaillant dans Perl ne peut pas reconnaître que la LValue est imposante sur le contexte de la liste sur la mission, ils ne vont pas aller très loin. Plutôt que de cacher ces caractéristiques des personnes, ceux qui les comprennent devraient aider les autres à les utiliser correctement.


@Eric il ne s'agit pas de ne pas comprendre les contextes. Son que vous vous attendiez à ce que Build_Hash () renvoie quelque chose de différent dans le contexte de la liste. Ne croyez pas que les études de l'utilisateur et se souvient pour toujours de la documentation de chaque fonction. Son composé dans ce mon ($ foo) et mon $ foo est assez facile à échanger avec désinvolture. Aussi fonction (build_hash ()) . Oups. Des bugs subtils manqués facilement. Enfin, le réaménagement d'un hachage n'a pas l'utilité du retour d'une liste. Un hachage doit être coincé dans une variable pour être utile. Le retour d'une liste peut être utilisé implicitement, style LISP. Donc, je questionne la valeur.



3
votes

En ce qui concerne le retour d'un hachage d'un fonction, normalement, vous devriez revenir le hachage lui-même, pas une référence. Tu pourrait utiliser une référence si le hachage est énorme et la mémoire ou le temps est une préoccupation, Mais cela ne devrait pas être votre premier souci - Obtenir le code du code est.

Je vais devoir être en désaccord avec éther ici. Il y avait un moment où j'ai pris cette position, mais je me suis rapidement retrouvé descendre dans un enfer de devoir me rappeler que Sub S est retourné hachage et qui a renvoyé HashRefs, qui était un obstacle assez grave pour simplement obtenir le code travail. Il est important de normaliser sur toujours renvoyer un hachage / tableau ou toujours renvoyer un hashref / arrayref, à moins que vous ne vouliez pas vous trébucher constamment sur vous-même.

Quant auxquels standardiser, je vois plusieurs avantages d'aller avec des références:

  • Lorsque vous retournez un hachage ou une matrice, ce que vous retournez réellement est une liste contenant une copie aplatie du hachage / matrice d'origine. Tout comme passer dans les paramètres de hachage / tableau vers un sous , cela a l'inconvénient que vous ne pouvez envoyer qu'une liste à la fois. Accordé, vous n'avez pas souvent besoin de retourner plusieurs listes de valeurs, mais cela se produit, alors pourquoi choisir de standardiser de faire des choses de manière à l'exclure?

  • Les performances (généralement négligeables) et les avantages de la mémoire du renvoi d'un scalaire unique plutôt que d'une partie de données potentiellement beaucoup plus importante.

  • Il maintient la cohérence avec le code de l'OO, qui transmet fréquemment des objets (c'est-à-dire des références bénies) d'avant en avant.

  • Si, pour une raison quelconque, il est important que vous ayez une copie fraîche du hachage / matrice plutôt que d'une référence à l'original, le code d'appel peut facilement en faire un, comme le démontrant l'OP dans C .pl . Si vous retournez une copie du hachage, il n'ya aucun moyen que l'appelant puisse le tourner en une référence à l'original. (Dans les cas où cela est avantageux, la fonction peut effectuer une copie et renvoyer une référence à la copie, protégeant ainsi l'original tout en évitant également " ce renvoie hachage, que Retourne Hashrefs "Hell j'ai mentionné plus tôt.)

  • Comme Schwern a mentionné, c'est vraiment agréable de pouvoir faire mon $ foo = $ obj-> quelque_data -> {key}

    Le seul avantage que je puisse voir à Toujours Retourner les hachages / matrices est qu'il est plus facile pour ceux qui ne comprennent pas les références ou ne sont pas à l'aise de travailler avec eux. Étant donné que le confort des références prend des semaines ou des mois à développer, suivis de années ou de décennies de travailler avec elles couramment, je ne considère pas cela un avantage significatif.


1 commentaires

+1, le maintien de la cohérence est un bon point. Cependant, étant donné que j'utilise des tableaux plus souvent en tant que matrices que j'utilise des hachage comme hatupes, et comme il y aurait beaucoup plus de déséroférences / copie de sécurité pour les rayons REFS, je pense qu'ils devraient être traités différemment.