Ceci est mon premier programme Python -
Exigence: Lisez un fichier composé de {userid de l'ADID} dans chaque ligne. Pour chaque ADID, imprimez le nombre d'userids uniques. P>
Voici mon code, placez-la de la lecture des documents Python. Pourriez-vous me donner des commentaires sur la façon dont je peux écrire cela en plus de python-ish? P>
code: p> merci. P> p>
8 Réponses :
Vous pouvez raccourcir la boucle pour cela:
for row in reader: adDict.setdefault(row[0], set()).add(row[1])
+1 - Nice! J'aurais aimé savoir la méthode SetDefault plus tôt!
Cool - Seul SetDefault (rangée [0], Set ()) renvoie une instance de jeu, puis nous faisons une ajout sur cela.
Les seules modifications que je ferais sont extraites de plusieurs éléments du lecteur à la fois et à l'aide de formatage de chaîne pour les instructions d'impression.
import csv adDict = {} reader = csv.reader(open("some.csv"), delimiter=' ') # Can extract multiple elements from a list in the iteration statement: for adId, userId in reader: if ( adId in adDict ): adDict[adId].add(userId) else: adDict[adId] = set(userId) for key, value in adDict.items(): # I believe this gives you more control over how things are formatted: print ("%s, %d" % (key, len(value)))
+1 - Bien que Notez que Python organisera une exception si le fichier CSV adopté n'a pas exactement 2 colonnes dans chaque rangée.
Félicitations, votre code est très gentil. Il y a quelques petites astuces que vous pourriez utiliser pour le rendre plus court / plus simple.
Il y a un type d'objet Nifty appelé DablierDict fourni par le module Collections. Au lieu de devoir vérifier si l'addict a une clé ADID, vous pouvez configurer un indice de défaillance qui agit comme une dicte régulière, sauf qu'il vous fournit automatiquement un ensemble vide () lorsqu'il n'y a pas de clé. Vous pouvez donc changer p> à simplement p> aussi, au lieu de p> Vous pouvez raccourcir cela à p> #!/usr/bin/env python
import csv
from collections import defaultdict
adDict = defaultdict(set)
reader = csv.reader(open("some.csv"), delimiter=' ')
for adId,userId in reader:
adDict[adId].add(userId)
for key,value in adDict.iteritems():
print (key, ',' , len(value))
Cool - Je vais lire des collections pour des astuces plus astucieuses. En outre, pourquoi dirions-nous «Importer CSV» mais avoir à dire «des collections importer des idées de défaillance»?
@Schitti - en utilisant à partir d'un raccourci. Cela signifie que vous pouvez taper defaultdict plutôt que Collections.defaultDict. Il est totalement facultatif, cependant, en important le symbole defaultDict dans l'espace de noms du module, il y a d'autres effets utiles qu'un programmeur avancé pourrait aimer.
@Schitti - une autre forme fonctionnera. Si vous souhaitez simplement utiliser l'instruction code> Importer CODE>, vous pouvez dire importer des collections.defaultDict code> - mais à chaque fois que vous l'utilisez, vous devez y référer comme
Collections.DefaultDict code>. Au lieu de cela, comme vous pouvez le constater dans la réponse de ~ Unutbu, vous devez maintenant seulement référence à celui-ci comme
defaultDict code>. Vous pouvez également modifier le nom d'un module lorsque vous l'importaez; Par exemple,
importer des collections.defaultDict comme défdi code> ou
à partir de collections Importation de défautDict comme défdi code> - Vous pouvez ensuite utiliser
défdi code> au lieu de
defaultdict < / code>
pour la clé, la valeur dans d.items () code> est une bien meilleure pratique que
pour la clé en D: valeur = D [clé] code>. La première version visit chaque élément exactement une fois. La deuxième version visit chaque élément une fois pour obtenir la liste des touches, puis doit ensuite rechercher chaque clé de la dicte. C'est O (n) versus O (n * journal n). Je pense que dans ce cas particulier, l'argument de la lisibilité pourrait aller dans les deux sens, mais la différence de performance est suffisamment importante (en particulier pour les grands dicts) que la première version est le gagnant défini.
@Parker, merci pour votre commentaire intéressant! Tu m'avais convaincu, mais j'ai essayé d'écrire du code de démonstration. À ma surprise, il semble que clé en d code> peut être plus rapide que la touche
, valeur dans d.items () code>. Le code est le code que j'ai testé: Coller.ubuntu.com/341327 .
Python -MtimeIT -S "Test d'importation" "Test.key_in_d ()" Code> a pris 409 ms par boucle,
python -mtime -s "test d'importation" "test.key_in_d_items ()" Code> a pris 631 ms par boucle. Qu'est-ce que tu penses?
~ ~ Unutbu, quelques choses. Je suppose que vous êtes sur Python2 où articles () renvoie une liste. Je pensais à Python3 où il retourne un générateur. Pour obtenir le même comportement dans Python2, vous devez utiliser les iTeritems quelque peu plus laids (). Deuxièmement, vous ne faites rien avec valeur à l'intérieur de la boucle. C'est peut-être que Python était assez intelligent pour simplement optimiser les parties de celui-ci. Essayez peut-être de créer une liste de touches, de valoriser les tuples simplement pour vous assurer que les deux parties sont utilisées.
@ ~ Unutbu, je viens de le tester ici. "Pour la clé en D" était de 335ms, "pour la clé, la valeur en D.Items ()" était en effet plus élevée à 561 ms, mais "pour la clé, la valeur de D.iteritems ()" était le gagnant défini à 206 ms. De toute évidence, pour un si grand dict, la création d'une liste des paires de la valeur clé a pris assez de temps et de mémoire. :)
@Parker: merveilleux. Merci d'avoir souligné cela. Je monte ma réponse en conséquence.
Quelques morceaux et quelques morceaux:
pour extraire la liste des lignes dans des variables: p> La déclaration IF n'a pas besoin d'accolades: P> try:
adDict[adId].add(userId)
except KeyError:
adDict[adId] = set(userId)
Oui, bien que peut-être l'inconvénient est que la logique basée sur des exceptions est plus difficile à comprendre.
au lieu de: Utiliser une séquence automatique de la séquence Déballage: p> in: p> Vous n'avez pas besoin de parenthèses. p> au lieu de: p> Utilisez ou, si vous n'êtes pas autorisé à utiliser d'autres modules par votre professeur, utilisez Lors de l'impression: p> à l'aide de la formatage de chaîne peut être plus facile à formater: p> ou, si vous 'RE UTILISATION PYTHON 3: P> defaultdict code>: P>
setingdefault () code>: p>
print ("{0},{1}".format (key, len(value)))
Merci John! Je suis dans l'industrie codant dans c au cours des 5 dernières années, donc aucun professeur
Ah désolé; Ce type de problème est souvent assigné que les devoirs pour commencer les étudiants.
Étant donné que vous n'avez qu'un fichier space délimité, je ferais:
from __future__ import with_statement from collections import defaultdict ads = defaultdict(set) with open("some.csv") as f: for ad, user in (line.split(" ") for line in f): ads[ad].add(user) for ad in ads: print "%s, %s" % (ad, len(ads[ad]))
Merci. Cela évite de créer une nouvelle classe de lecteur que je présume. Impossible de vous uppoter depuis ma réputation <15.
J'aime ça. J'allais juste vous recommander d'utiliser defaultDict (défini) code>. Cependant, ce code décompose chaque ligne dans un tuple, en supposant que chaque ligne ne comporte que deux éléments. Le code de l'OP n'a pas fait cette hypothèse.
@HUGHDBROWN: Vous avez raison sur l'hypothèse que chaque ligne n'a que deux éléments. Cependant, la question de l'OP affirme explicitement que son dossier n'a que deux éléments sur chaque ligne. Dans ce cas, je pense qu'il est acceptable de simplement échouer (avec une erreur de déballage de tuple) s'il existe un nombre différent d'éléments sur une ligne. Évidemment, dans un script plus durci de production, vous voudrez coder plus de manière défensive.
La ligne de code: est peu susceptible de faire ce que vous voulez - il traitera de la chaîne Pour faire un ensemble avec un seul Article, utilisez C'est un bug raisonnablement fréquent pour que je voulais donc l'expliquer clairement. Qui étant dit, Je voudrais également éviter le kenta-overkill de userid code> comme une séquence de lettres, donc par exemple si
userID code> était
AleAx code> Vous obtiendriez un ensemble avec quatre articles, comme, par exemple,
Set (['a', 'L', 'E', 'E', 'x']) code>. Plus tard, un
.add (userid) code> Lorsque
userid code> est
AleAx code> ajoutera à nouveau un cinquième élément, la chaîne
'Aleax' code>, parce que
.add code> (différemment de l'initialiseur de jeu, qui prend un appareil itable comme argument) prend un seul élément comme argument. p>
SET ([ID utilisateur]) code> à la place. P>
defaultDict code> comme suggéré dans d'autres réponses est clairement la bonne approche (évitez
setingdefault code>, qui n'a jamais été une bonne conception et n'a pas de bonnes performances non plus, non plus, comme étant jolie trouble). P>
csv code> en faveur d'une boucle simple avec un .split et .strip sur chaque ligne ... < / p> p>
Oui à Collections.DefaultDict (SET) CODE>.
Il y a de bonnes réponses ici.
Un astuce que j'aime particulièrement est de rendre mon code plus facile à réutiliser à l'avenir, comme p> maintenant que vous pouvez importer votre analyseur CSV d'un autre module et obtenez un accès programmatique à Adict. p> p>
+1 J'aime l'intention derrière votre message - vous apprendrez également beaucoup en parcourant d'autres questions sous la balise Python ici au débordement de la pile.
@Mark - Je reçois beaucoup ça, généralement quelqu'un me demande si mon nom d'utilisateur doit être prononcé comme Chicago. M'a pris un moment pour l'obtenir pour la première fois que quelqu'un m'a cependant demandé. Mais non, mon prénom commence par un nom S et Mylast est Chitti, prononcé Cheeeee.