Comment se démarquer dans une entrevue de codage Python – Real Python

By | avril 11, 2019

Expert Python

Vous avez réussi à passer l’appel téléphonique avec le recruteur et il est temps de montrer que vous savez comment résoudre les problèmes avec le code actuel. Qu’il s’agisse d’un exercice HackerRank, d’un devoir à faire à la maison ou d’un entretien avec un tableau blanc sur site, c’est le moment de prouver vos compétences en entretien de codage.

Mais les entretiens ne concernent pas uniquement la résolution de problèmes: ils montrent également que vous pouvez écrire du code de production propre. Cela signifie que vous avez une connaissance approfondie des fonctionnalités intégrées et des bibliothèques de Python. Cette connaissance montre aux entreprises que vous pouvez agir rapidement sans dupliquer la fonctionnalité fournie avec le langage simplement parce que vous ne savez pas qu’elle existe.

À Vrai python, nous avons réfléchi ensemble et discuté des outils que nous sommes toujours impressionnés de voir dans les entrevues de codage. Cet article décrit le meilleur de cette fonctionnalité, en commençant par les fonctions intégrées de Python, puis par le support natif de Python pour les structures de données, et enfin par la puissante bibliothèque standard de Python (et souvent sous-estimée).

Dans cet article, vous apprendrez comment:

  • Utilisation énumérer() parcourir les deux indices et les valeurs
  • Déboguer le code problématique avec point d'arrêt ()
  • Formater efficacement les chaînes avec des chaînes de caractères
  • Trier les listes avec des arguments personnalisés
  • Utilisez des générateurs plutôt que des listes de compréhension pour économiser de la mémoire
  • Définir les valeurs par défaut lors de la recherche de clés de dictionnaire
  • Comptez les objets hashable avec le collections.Counter classe
  • Utilisez la bibliothèque standard pour obtenir des listes de permutations et de combinaisons

Sélectionnez la fonction intégrée appropriée pour le travail

Python a une grande bibliothèque standard mais seulement une petite bibliothèque de fonctions intégrées, toujours disponibles et n’ayant pas besoin d’être importées. Cela vaut la peine de passer en revue chacune d’elles, mais jusqu’à ce que vous ayez la chance de le faire, voici quelques fonctions intégrées qui méritent d’être comprises, et dans le cas de certaines d’entre elles, quelles alternatives utiliser.

Itérer avec énumérer() Au lieu de intervalle()

Ce scénario peut apparaître plus que tout autre dans les entrevues de codage: vous avez une liste d'éléments et vous devez parcourir la liste avec accès aux index et aux valeurs.

Il existe une question d’entrevue de codage classique appelée FizzBuzz qui peut être résolue en effectuant une itération sur les indices et les valeurs. Dans FizzBuzz, vous recevez une liste d'entiers. Votre tâche consiste à:

  1. Remplacer tous les entiers divisibles par 3 avec "pétiller"
  2. Remplacer tous les entiers divisibles par 5 avec "bourdonner"
  3. Remplacer tous les entiers divisibles par les deux 3 et 5 avec "fizzbuzz"

Les développeurs vont souvent résoudre ce problème avec intervalle():

>>>

>>> Nombres = [[[[45, 22, 14, 65, 97, 72]
>>> pour je dans intervalle(len(Nombres)):
...     si Nombres[[[[je] % 3 == 0 et Nombres[[[[je] % 5 == 0:
...         Nombres[[[[je] = 'fizzbuzz'
...     elif Nombres[[[[je] % 3 == 0:
...         Nombres[[[[je] = 'pétiller'
...     elif Nombres[[[[je] % 5 == 0:
...         Nombres[[[[je] = 'bourdonner'
...
>>> Nombres
['fizzbuzz', 22, 14, 'buzz', 97, 'fizz']

Range vous permet d'accéder aux éléments de Nombres par index et est un outil utile pour certaines situations. Mais dans ce cas, où vous voulez obtenir l’indice et la valeur de chaque élément en même temps, une solution plus élégante utilise énumérer():

>>>

>>> Nombres = [[[[45, 22, 14, 65, 97, 72]
>>> pour je, num dans énumérer(Nombres):
...     si num % 3 == 0 et num % 5 == 0:
...         Nombres[[[[je] = 'fizzbuzz'
...     elif num % 3 == 0:
...         Nombres[[[[je] = 'pétiller'
...     elif num % 5 == 0:
...         Nombres[[[[je] = 'bourdonner'
...
>>> Nombres
['fizzbuzz', 22, 14, 'buzz', 97, 'fizz']

Pour chaque élément, énumérer() retourne un compteur et la valeur de l'élément. Le compteur par défaut à 0, qui constitue également l’index de l’élément. Ne voulez pas commencer votre compte à 0? Il suffit d'utiliser l'option début paramètre pour définir un décalage:

>>>

>>> Nombres = [[[[45, 22, 14, 65, 97, 72]
>>> pour je, num dans énumérer(Nombres, début=52):
...     impression(je, num)
...
52 45
53 22
54 14
55 65
56 97
57 72

En utilisant le début paramètre, nous accédons à tous les mêmes éléments, en commençant par le premier index, mais notre décompte commence à partir de la valeur entière spécifiée.

Utiliser la liste des compréhensions au lieu de carte() et filtre()

“Je pense que supprimer les filtres filter () et map () n'est pas controversé[.]”

Guido van Rossum, créateur de Python

Il a peut-être eu tort de dire que cela n’était pas controversé, mais Guido avait de bonnes raisons de vouloir supprimer carte() et filtre() de Python. Une des raisons est que Python prend en charge les compréhensions de liste, qui sont souvent plus faciles à lire et supportent les mêmes fonctionnalités que carte() et filtre().

Voyons d’abord comment nous structurerions un appel à carte() et la compréhension de la liste équivalente:

>>>

>>> Nombres = [[[[4, 2, 1, 6, 9, 7]
>>> def carré(X):
...     revenir X*X
...
>>> liste(carte(carré, Nombres))
[16, 4, 1, 36, 81, 49]

>>> [[[[carré(X) pour X dans Nombres]
[16, 4, 1, 36, 81, 49]

Les deux approches, utilisant carte() et la compréhension de liste, renvoient les mêmes valeurs, mais la compréhension de liste est plus facile à lire et à comprendre.

Maintenant, nous pouvons faire la même chose pour le filtre() et sa compréhension de liste équivalente:

>>>

>>> def est impair(X):
...    revenir bool(X % 2)
...
>>> liste(filtre(est impair, Nombres))
[1, 9, 7]

>>> [[[[X pour X dans Nombres si est impair(X)]
[1, 9, 7]

Comme on a vu avec carte(), la filtre() et les approches de compréhension de liste retournent la même valeur, mais la compréhension de liste est plus facile à suivre.

Les développeurs issus d’autres langues peuvent ne pas être d’accord sur le fait que la compréhension des listes est plus facile à lire que carte() et filtre(), mais selon mon expérience, les débutants sont en mesure de saisir les compréhensions de listes beaucoup plus intuitivement.

Quoi qu’il en soit, vous vous tromperez rarement en utilisant une compréhension de liste dans une interview avec codage, car vous saurez que vous savez ce qui est le plus courant en Python.

Déboguer avec point d'arrêt () Au lieu de impression()

Vous avez peut-être débogué un petit problème en ajoutant impression() à votre code et voir ce qui a été imprimé. Cette approche fonctionne bien au début mais devient rapidement encombrante. De plus, dans un cadre d’interview avec codage, vous ne voulez plus impression() des appels parsemés dans votre code.

Au lieu de cela, vous devriez utiliser un débogueur. Pour les bogues non triviaux, c’est presque toujours plus rapide que d’utiliser impression()Et comme le débogage est une partie importante du logiciel d’écriture, cela montre que vous savez utiliser des outils qui vous permettront de vous développer rapidement.

Si vous utilisez Python 3.7, vous n’avez rien à importer, vous pouvez simplement appeler point d'arrêt () à l’emplacement de votre code où vous souhaitez accéder au débogueur:

# Du code compliqué avec des bugs

point d'arrêt()

Appel point d'arrêt () va vous mettre dans pdb, qui est le débogueur Python par défaut. Sur Python 3.6 et versions antérieures, vous pouvez faire de même en important pdb explicitement:

importation pdb; pdb.set_trace()

Comme point d'arrêt (), pdb.set_trace () va vous mettre dans le pdb débogueur. Ce n’est tout simplement pas aussi propre et c’est un peu plus à retenir.

Il existe d’autres débogueurs disponibles que vous voudrez peut-être essayer, mais pdb fait partie de la bibliothèque standard, elle est donc toujours disponible. Quel que soit le débogueur que vous préférez, il vaut la peine de l’essayer pour s’habituer au flux de travail avant d’être dans un cadre d’interview avec codage.

Mettre en forme des chaînes avec f-Strings

Python a beaucoup de façons différentes de gérer le formatage des chaînes, et il peut être difficile de savoir quoi utiliser. En fait, nous abordons le formatage en profondeur dans deux articles distincts: l’un sur le formatage des chaînes en général et l’autre sur les f-string. Dans une interview avec codage, où vous utilisez (espérons-le) Python 3.6+, l’approche de formatage suggérée est la chaîne de caractères f de Python.

Les f-strings prennent en charge l'utilisation du mini-langage de formatage de chaîne, ainsi que la puissante interpolation de chaîne. Ces fonctionnalités vous permettent d’ajouter des variables ou même des expressions Python valides et de les faire évaluer au moment de l’exécution avant de les ajouter à la chaîne:

>>>

>>> def get_name_and_decades(prénom, âge):
...     revenir F"Mon nom est prénom    et j'ai age / 10: .5f décades. "
...
>>> get_name_and_decades("Maria", 31)
Je m'appelle Maria et j'ai 3.10000 ans.

La chaîne de caractères vous permet de mettre Maria dans la chaîne et ajouter son âge avec le formatage souhaité en une seule opération succincte.

Le seul risque à prendre en compte est que, si vous indiquez des valeurs générées par l'utilisateur, cela peut entraîner des risques de sécurité, auquel cas les chaînes de modèle peuvent constituer une option plus sûre.

Trier les listes complexes avec triés ()

Un grand nombre de questions d'entrevue de codage nécessitent une sorte de tri et il existe de nombreuses façons valables de trier les éléments. À moins que l’enquêteur veuille que vous mettiez en œuvre votre propre algorithme de tri, il est généralement préférable d’utiliser triés ().

Vous avez probablement déjà vu les utilisations les plus simples du tri, telles que le tri de listes de nombres ou de chaînes dans un ordre croissant ou décroissant:

>>>

>>> triés([[[[6,5,3,7,2,4,1])
[1, 2, 3, 4, 5, 6, 7]

>>> triés([[[['chat', 'chien', 'guépard', 'rhinocéros', 'ours'], sens inverse=Vrai)
['rhino', 'dog', 'cheetah', 'cat', 'bear]

Par défaut, triés () a trié les entrées par ordre croissant, et le sens inverse L'argument du mot-clé le trie par ordre décroissant.

Il est utile de connaître l’argument optionnel du mot clé clé cela vous permet de spécifier une fonction qui sera appelée sur chaque élément avant le tri. L'ajout d'une fonction permet de définir des règles de tri personnalisées, particulièrement utiles si vous souhaitez trier des types de données plus complexes:

>>>

>>> animaux = [[[[
...     'type': 'manchot', 'prénom': 'Stéphanie', 'âge': 8,
...     'type': 'l'éléphant', 'prénom': 'Devon', 'âge': 3,
...     'type': 'puma', 'prénom': 'Moe', 'âge': 5,
... ]
>>> triés(animaux, clé=lambda animal: animal[[[['âge'])
[[[[
                'type': 'éléphant', 'nom': 'Devon', 'age': 3,
                'type': 'puma', 'nom': 'Moe', 'age': 5,
                'type': 'pingouin', 'nom': 'Stéphanie,' age ': 8,
]

En passant une fonction lambda qui renvoie l’âge de chaque élément, vous pouvez facilement trier une liste de dictionnaires en fonction d’une valeur unique de chacun de ces dictionnaires. Dans ce cas, le dictionnaire est maintenant trié par ordre croissant d’âge.

Exploiter efficacement les structures de données

Les algorithmes attirent beaucoup d'attention lors du codage des entretiens, mais les structures de données sont encore plus importantes. Dans un contexte d’interview avec codage, le choix de la structure de données appropriée peut avoir un impact majeur sur les performances.

Au-delà des structures de données théoriques, Python intègre des fonctionnalités puissantes et pratiques intégrées dans ses implémentations de structures de données standard. Ces structures de données sont extrêmement utiles pour coder les entretiens, car elles vous offrent de nombreuses fonctionnalités par défaut et vous permettent de consacrer votre temps à d’autres aspects du problème.

Stocker des valeurs uniques avec des ensembles

Vous aurez souvent besoin de supprimer les éléments en double d'un jeu de données existant. Les nouveaux développeurs le font parfois avec des listes alors qu'ils devraient utiliser des ensembles, ce qui impose l'unicité de tous les éléments.

Imaginez que vous avez une fonction nommée get_random_word (). Il retournera toujours une sélection aléatoire parmi un petit groupe de mots:

>>>

>>> importation au hasard
>>> tous les mots = "Tous les mots dans le monde".Divisé()
>>> def get_random_word():
...    revenir au hasard.choix(tous les mots)

Vous êtes censé appeler get_random_word () à plusieurs reprises pour obtenir 1000 mots aléatoires, puis renvoyer une structure de données contenant chaque mot unique. Voici deux approches communes, non optimales et une bonne approche.

Mauvaise approche

get_unique_words () stocke les valeurs dans une liste puis convertit la liste en un ensemble:

>>>

>>> def get_unique_words():
...     mots = []
...     pour _ dans intervalle(1000):
...         mots.ajouter(get_random_word())
...     revenir ensemble(mots)
>>> get_unique_words()
'monde', 'tous', 'les', 'mots'

Cette approche n’est pas terrible, mais elle crée inutilement une liste puis la convertit en un ensemble. Les intervieweurs remarquent presque toujours (et posent des questions sur) ce type de choix de conception.

Pire approche

Pour éviter la conversion d'une liste en un ensemble, vous stockez maintenant des valeurs dans une liste sans utiliser d'autres structures de données. Vous testez ensuite l'unicité en comparant les nouvelles valeurs avec tous les éléments actuellement dans la liste:

>>>

>>> def get_unique_words():
...     mots = []
...     pour _ dans intervalle(1000):
...         mot = get_random_word()
...         si mot ne pas dans mots:
...             mots.ajouter(mot)
...     revenir mots
>>> get_unique_words()
['world', 'all', 'the', 'words']

C'est pire que la première approche, car vous devez comparer chaque nouveau mot à chaque mot déjà dans la liste. Cela signifie qu'à mesure que le nombre de mots augmente, le nombre de recherches augmente quadratiquement. En d'autres termes, la complexité temporelle augmente de l'ordre de O (N²).

Bonne approche

Maintenant, vous ignorez complètement l’utilisation des listes et utilisez un ensemble depuis le début:

>>>

>>> def get_unique_words():
...     mots = ensemble()
...     pour _ dans intervalle(1000):
...         mots.ajouter(get_random_word())
...     revenir mots
>>> get_unique_words()
'monde', 'tous', 'les', 'mots'

Cela peut ne pas sembler très différent des autres approches, sauf que vous utilisez un ensemble depuis le début. Si vous considérez ce qui se passe au sein de .ajouter()Cela ressemble même à la deuxième approche: récupérez le mot, vérifiez s’il fait déjà partie de l’ensemble et, dans le cas contraire, ajoutez-le à la structure de données.

Alors, pourquoi utiliser un ensemble différent de la deuxième approche?

C’est différent parce que les ensembles stockent les éléments d’une manière qui permet de vérifier si une valeur est dans l’ensemble ou non, contrairement aux listes, qui nécessitent des recherches dans le temps linéaire. La différence de temps de référence signifie que la complexité temporelle pour l'ajout à un ensemble augmente à un taux de O (N), ce qui est bien meilleur que le O (N²) de la deuxième approche dans la plupart des cas.

Économiser de la mémoire avec des générateurs

Les listes de compréhension sont des outils pratiques mais peuvent parfois conduire à une utilisation inutile de la mémoire.

Imaginez que l’on vous demande de trouver la somme des 1 000 premiers carrés parfaits, en commençant par 1. Vous connaissez les listes compréhensives, vous codez donc rapidement une solution efficace:

>>>

>>> somme([[[[je * je pour je dans intervalle(1, 1001)])
333833500

Votre solution dresse une liste de chaque carré parfait compris entre 1 et 1 000 000 et additionne les valeurs. Votre code renvoie la bonne réponse, mais votre interlocuteur commence alors à augmenter le nombre de carrés parfaits dont vous avez besoin de faire la somme.

Au début, votre fonction n'arrête pas de trouver la bonne réponse, mais elle commence à ralentir jusqu'à ce que le processus semble durer une éternité. Ceci est la dernière chose que vous souhaitiez voir dans une interview de codage.

Que se passe t-il ici?

Il dresse la liste de tous les carrés parfaits que vous avez demandés et les récapitule tous. Une liste de 1 000 carrés parfaits n’est peut-être pas très volumineuse en informatique, mais 100 millions ou 1 milliard, c’est un peu d’information et peut facilement surcharger les ressources en mémoire disponibles de votre ordinateur. C’est ce qui se passe ici.

Heureusement, il existe un moyen rapide de résoudre le problème de mémoire. Vous venez de remplacer les crochets avec des parenthèses:

>>>

>>> somme((je * je pour je dans intervalle(1, 1001)))
333833500

En remplaçant les crochets, votre compréhension de la liste se transforme en une expression génératrice. Les expressions de générateur conviennent parfaitement lorsque vous savez que vous souhaitez récupérer les données d’une séquence sans avoir à accéder à toutes les données en même temps.

Au lieu de créer une liste, l’expression génératrice renvoie un Générateur objet. Cet objet sait où il se trouve dans l'état actuel (par exemple, i = 49) et calcule uniquement la valeur suivante à la demande.

Donc quand somme itère sur l'objet générateur en appelant .__suivant__() à plusieurs reprises, le générateur vérifie ce je est égal, calcule je * je, incréments je en interne, et renvoie la valeur appropriée à somme. La conception permet aux générateurs d'être utilisés sur des séquences de données volumineuses, car un seul élément existe en mémoire à la fois.

Définir les valeurs par défaut dans les dictionnaires avec .obtenir() et .définir par defaut()

L’une des tâches de programmation les plus courantes consiste à ajouter, modifier ou récupérer un élément figurant ou non dans un dictionnaire. Les dictionnaires Python ont des fonctionnalités élégantes pour rendre ces tâches propres et faciles, mais les développeurs recherchent souvent explicitement les valeurs lorsque cela n’est pas nécessaire.

Imaginez que vous avez un dictionnaire nommé cow-boyet vous voulez avoir le nom de ce cow-boy. Une approche consiste à vérifier explicitement la clé avec un conditionnel:

>>>

>>> cow-boy = 'âge': 32, 'cheval': 'mustang', 'hat_size': 'grand'
>>> si 'prénom' dans cow-boy:
...     prénom = cow-boy[[[['prénom']
... autre:
...     prénom = "L'homme sans nom"
...
>>> prénom
"L'homme sans nom"

Cette approche vérifie d’abord si le prénom La clé existe dans le dictionnaire et, le cas échéant, elle renvoie la valeur correspondante. Sinon, il retourne une valeur par défaut.

Bien que la recherche explicite de clés fonctionne, elle peut facilement être remplacée par une ligne si vous utilisez .obtenir():

>>>

>>> prénom = cow-boy.obtenir('prénom', "L'homme sans nom")

obtenir() effectue les mêmes opérations que lors de la première approche, mais elles sont maintenant gérées automatiquement. Si la clé existe, la valeur appropriée sera renvoyée. Sinon, la valeur par défaut sera renvoyée.

Mais que se passe-t-il si vous voulez mettre à jour le dictionnaire avec une valeur par défaut tout en accédant au prénom clé? .obtenir() ne vous aide pas vraiment ici, alors il vous reste à vérifier explicitement la valeur à nouveau:

>>>

>>> si 'prénom' ne pas dans cow-boy:
...     cow-boy[[[['prénom'] = "L'homme sans nom"
...
>>> prénom = cow-boy[[[['prénom']

Vérifier la valeur et définir une valeur par défaut est une approche valide et facile à lire, mais Python propose une méthode plus élégante avec .définir par defaut():

>>>

>>> prénom = cow-boy.définir par defaut('prénom', "L'homme sans nom")

.définir par defaut() accomplit exactement la même chose que l'extrait ci-dessus. Il vérifie si prénom existe dans cow-boyet si oui, il renvoie cette valeur. Sinon, cela définit cow-boy['name'] à L'homme sans nom et retourne la nouvelle valeur.

Profitez de la bibliothèque standard de Python

Par défaut, Python est doté de nombreuses fonctionnalités qui ne sont qu’un importation déclaration loin. C’est puissant en soi, mais savoir tirer parti de la bibliothèque standard peut renforcer vos compétences en matière d’interviews de codage.

Il est difficile de sélectionner les éléments les plus utiles parmi tous les modules disponibles. Cette section ne portera donc que sur un petit sous-ensemble de ses fonctions d’utilité. J'espère que ces informations vous seront utiles pour coder les entretiens et vous donneront l'envie d'en savoir plus sur les fonctionnalités avancées de ces modules et d'autres.

Manipuler les clés de dictionnaire manquantes avec collections.defaultdict ()

.obtenir() et .définir par defaut() fonctionne bien lorsque vous définissez une valeur par défaut pour une clé unique, mais il est courant de vouloir une valeur par défaut pour toutes les clés non définies, en particulier lors de la programmation dans un contexte d’interview codé.

Imaginez que vous avez un groupe d’étudiants et que vous devez suivre leurs notes aux devoirs. La valeur d'entrée est une liste de n-uplets au format (nom_étudiant, grade), mais vous souhaitez rechercher facilement toutes les notes d’un étudiant sans parcourir la liste.

Une façon de stocker les données de notes utilise un dictionnaire qui mappe les noms des étudiants à des listes de notes:

>>>

>>> Student_grades = 
>>> grades = [[[[
...     ('Elliot', 91),
...     ('neelam', 98),
...     ('bianca', 81),
...     ('Elliot', 88),
... ]
>>> pour prénom, qualité dans grades:
...     si prénom ne pas dans Student_grades:
...         Student_grades[[[[prénom] = []
...     Student_grades[[[[prénom].ajouter(qualité)
...
>>> Student_grades
'Elliot': [91, 88], 'neelam': [98], 'bianca': [81]

Dans cette approche, vous parcourez les étudiants et vérifiez si leurs noms sont déjà des propriétés du dictionnaire. Sinon, vous les ajoutez au dictionnaire avec une liste vide comme valeur par défaut. Vous ajoutez ensuite leurs notes réelles à la liste des notes de cet élève.

Mais il existe une approche encore plus propre qui utilise un defaultdict, qui étend la norme dict fonctionnalité pour vous permettre de définir une valeur par défaut qui sera utilisée si la clé n’existe pas:

>>>

>>> de collections importation defaultdict
>>> Student_grades = defaultdict(liste)
>>> pour prénom, qualité dans grades:
...     Student_grades[[[[prénom].ajouter(qualité)

Dans ce cas, vous créez un defaultdict qui utilise le liste() constructeur sans arguments comme méthode de fabrique par défaut. liste() sans argument renvoie une liste vide, donc defaultdict appels liste() si le nom n’existe pas et permet ensuite d’ajouter la note. Si vous voulez avoir du chic, vous pouvez également utiliser une fonction lambda comme valeur d’usine pour renvoyer une constante arbitraire.

Tirer parti d'un defaultdict peut conduire à un code d’application plus propre car vous n’aurez plus à vous soucier des valeurs par défaut au niveau clé. Au lieu de cela, vous pouvez les gérer une fois au defaultdict puis agissez comme si la clé était toujours présente.

Compter les objets hashable collections.Counter

Vous avez une longue chaîne de mots sans ponctuation ni majuscule et vous voulez compter combien de fois chaque mot apparaît.

Vous pouvez utiliser un dictionnaire ou defaultdict et incrémenter les comptes, mais collections.Counter fournit un moyen plus propre et plus pratique de faire exactement cela. Counter est une sous-classe de dict qui utilise 0 comme valeur par défaut pour tout élément manquant et facilite le comptage des occurrences d'objets:

>>>

>>> de collections importation Compteur
>>> mots = "s'il y avait il y avait mais si 
... il n'y avait pas il n'y avait pas ".Divisé()
>>> compte = Compteur(mots)
>>> compte
Compteur ('si': 2, 'là': 4, 'était': 4, 'pas': 2, 'mais': 1)

Lorsque vous passez dans la liste des mots à Compteur, il stocke chaque mot avec le nombre de fois où ce mot est apparu dans la liste.

Êtes-vous curieux de savoir quels étaient les deux mots les plus courants? Juste utiliser .Le plus commun():

>>>

>>> compte.Le plus commun(2)
[('there', 4), ('was', 4)]

.Le plus commun() est une méthode pratique et renvoie simplement le n les entrées les plus fréquentes en nombre.

Accéder aux groupes de chaînes communs avec chaîne Constantes

C’est le temps des anecdotes! Est 'A'> 'a' vrai ou faux?

C’est faux, car le code ASCII pour UNE a 65 ans, mais une est 97 et 65 n’est pas supérieur à 97.

Pourquoi la réponse est-elle importante? Parce que si vous voulez vérifier si un caractère fait partie de l’alphabet anglais, un moyen courant est de voir s’il se situe entre UNE et z (65 et 122 sur la carte ASCII).

Vérifier le code ASCII fonctionne, mais est maladroit et facile à gâcher dans le codage des entretiens, surtout si vous ne pouvez pas vous souvenir si les caractères ASCII minuscules ou majuscules sont prioritaires. Il est beaucoup plus facile d’utiliser les constantes définies dans le chaîne module.

Vous pouvez en voir un en cours d'utilisation dans is_upper (), qui indique si tous les caractères d’une chaîne sont des lettres majuscules:

>>>

>>> importation chaîne
>>> def is_upper(mot):
...     pour lettre dans mot:
...         si lettre ne pas dans chaîne.ascii_uppercase:
...             revenir Faux
...     revenir Vrai
...
>>> is_upper('Merci Geir')
Faux
>>> is_upper('LOL')
Vrai

is_upper () itère sur les lettres motet vérifie si les lettres font partie de string.ascii_uppercase. Si vous imprimez string.ascii_uppercase vous verrez que c’est juste une petite corde. La valeur est définie sur le littéral 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.

Tout chaîne les constantes ne sont que des chaînes de valeurs de chaîne fréquemment référencées. Ils comprennent les éléments suivants:

  • string.ascii_letters
  • string.ascii_uppercase
  • string.ascii_lowercase
  • string.digits
  • string.hexdigits
  • string.octdigits
  • string.punctuation
  • string.printable
  • string.whitespace

Celles-ci sont plus faciles à utiliser et, plus important encore, plus faciles à lire.

Générer des permutations et des combinaisons avec outils informatiques

Les intervieweurs aiment donner des scénarios réels pour que les entretiens de codage paraissent moins intimidants. C’est donc un exemple artificiel: vous allez dans un parc d’attractions et décidez de trouver tous les amis possibles qui pourraient s’asseoir ensemble sur des montagnes russes.

Si l’objectif principal de la question d’entrevue n’est pas de générer ces paires, il est probable que la génération de toutes les paires possibles n’est qu’une étape fastidieuse sur la voie d’un algorithme fonctionnel. Vous pouvez les calculer vous-même avec des boucles for imbriquées, ou vous pouvez utiliser le puissant outils informatiques bibliothèque.

outils informatiques dispose de plusieurs outils pour générer des séquences itérables de données d’entrée, mais pour l’instant nous allons nous concentrer sur deux fonctions communes: itertools.permutations () et itertools.combinations ().

itertools.permutations () construit une liste de toutes les permutations, ce qui signifie qu’il s’agit d’une liste de tous les regroupements possibles de valeurs d’entrée avec une longueur correspondant à la longueur. compter paramètre. le r L'argument de mot clé nous permet de spécifier le nombre de valeurs contenues dans chaque groupe:

>>>

>>> importation outils informatiques
>>> copains = [[[['Monique', 'Ashish', 'Devon', 'Bernie']
>>> liste(outils informatiques.permutations(copains, r=2))
[('Monique''Ashish')('Monique''Devon')('Monique''Bernie')[('Monique''Ashish')('Monique''Devon')('Monique''Bernie')[('Monique''Ashish')('Monique''Devon')('Monique''Bernie')[('Monique''Ashish')('Monique''Devon')('Monique''Bernie')
(«Ashish», «Monique»), («Ashish», «Devon»), («Ashish», «Bernie»),
("Devon", "Monique"), ("Devon", "Ashish"), ("Devon", "Bernie"),
('Bernie', 'Monique'), ('Bernie', 'Ashish'), ('Bernie', 'Devon')]

Avec les permutations, l’ordre des éléments compte, donc ('sam', 'devon') représente un appariement différent de celui ('devon', 'sam'), ce qui signifie qu'ils seraient tous deux inclus dans la liste.

itertools.combinations () construit des combinaisons. Ce sont aussi les regroupements possibles des valeurs d’entrée, mais maintenant l’ordre des valeurs n’a plus d’importance. Parce que ('sam', 'devon') et ('devon', 'sam') représenter la même paire, un seul d'entre eux serait inclus dans la liste de sortie:

>>>

>>> liste(outils informatiques.des combinaisons(copains, r=2))
[('Monique''Ashish')('Monique''Devon')('Monique''Bernie')[('Monique''Ashish')('Monique''Devon')('Monique''Bernie')[('Monique''Ashish')('Monique''Devon')('Monique''Bernie')[('Monique''Ashish')('Monique''Devon')('Monique''Bernie')
('Ashish', 'Devon'), ('Ashish', 'Bernie'), ('Devon', 'Bernie')]

Étant donné que l'ordre des valeurs est important pour les combinaisons, il y a moins de combinaisons que de permutations pour la même liste d'entrées. Encore une fois, parce que nous avons mis r à 2, chaque groupe a deux noms.

.combinations () et .permutations () ne sont que de petits exemples d’une bibliothèque puissante, mais même ces deux fonctions peuvent être très utiles lorsque vous essayez de résoudre rapidement un problème d’algorithme.

Conclusion: coder les superpouvoirs d'interview

Vous pouvez maintenant vous sentir à l'aise d'utiliser certaines des fonctionnalités standard moins courantes, mais plus puissantes, de Python lors de votre prochaine interview avec codage. Il y a beaucoup à apprendre sur la langue dans son ensemble, mais cet article aurait dû vous donner le point de départ pour aller plus loin tout en vous permettant d'utiliser Python plus efficacement lorsque vous interviewez.

Dans cet article, vous avez appris différents types d’outils standard pour améliorer vos compétences en matière d’interviews de codage:

  • Fonctions intégrées puissantes
  • Structures de données conçues pour gérer des scénarios courants avec à peine n'importe quel code
  • Paquets de bibliothèque standard offrant des solutions riches en fonctionnalités pour des problèmes spécifiques, vous permettant d'écrire un meilleur code plus rapidement

Les entretiens ne sont peut-être pas la meilleure approximation d’un développement logiciel réel, mais il est utile de savoir comment réussir dans n’importe quel environnement de programmation, même les entretiens. Heureusement, apprendre à utiliser Python au cours des entretiens de codage peut vous aider à comprendre la langue plus en profondeur, ce qui vous rapportera des fruits au cours de votre développement quotidien.