J'ai essayé d'implémenter le tri par fusion en Python avec le moins de lignes possible

Il est probablement naturel d'entendre que mes amis étudient de temps en temps l'implémentation d'algorithmes et travaillent sur l'implémentation de sortes de fusion. Un jeu mystérieux a eu lieu dans lequel il était préférable de le mettre en œuvre avec le moins de lignes possible car c'était un gros problème. J'ai entendu dire que mon ami voulait le faire en Python, alors j'ai décidé de le faire en Python. Je ne perdrai pas

règle

--Utilisez un tableau de données dans lequel les nombres de 1 à 10 sont disposés de manière aléatoire.

Le code de la partie commune est le suivant

from data import generate_data

data = generate_data() #Les nombres de 1 à 10 sont alignés en morceaux
print(data)

#Mis en œuvre ci-dessous

Il y a data.py dans un autre fichier, et la fonction generate_data là générera les données. Les données seront quelque chose comme [5, 1, 3, 9, 2, 8, 7, 4, 10, 6] ''. Je viens de créer correctement le contenu de data.py``, je vais donc l'omettre ici.

Résultat de la mise en œuvre

Quand je l'ai écrit selon les règles ci-dessus, c'est devenu comme ça.

from data import generate_data

data = generate_data() #Les nombres de 1 à 10 sont alignés en morceaux
print(data)

#Mis en œuvre ci-dessous
divide = lambda data: data if len(data) == 1 else [min(data), max(data)] if len(data) <= 2 else [divide([data[i] for i in range(len(data) // 2)]), divide([data[i] for i in range(len(data) // 2, len(data))])]
merge = lambda left, right: [right.pop(0) if len(left) == 0 else left.pop(0) if len(right) == 0 else left.pop(0) if left[0] < right[0] else right.pop(0) for i in range(len(left) + len(right))] if type(left[0]) is int and type(right[0]) is int else merge(left, merge(right[0], right[1])) if type(left[0]) is int else (merge(merge(left[0], left[1]), right) if type(right[0]) is int else merge(merge(left[0], left[1]), merge(right[0], right[1])))
print(merge(divide(data)[0], divide(data)[1]))

production


[5, 1, 3, 9, 2, 8, 7, 4, 10, 6]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Ce n'était pas un problème même si on me disait "Long. En trois lignes". Je vais l'expliquer pour le moment.

Écoulement brutal

Le tri de fusion semble être basé sur la "méthode de règle de division", et il semble que le tableau de données est une fois divisé à l'unité minimale, et les données sont correctement sélectionnées à partir de chaque donnée divisée, combinées, puis réorganisées. La personne qui a pensé Étant donné que de nombreux ancêtres ont expliqué divers détails de l'algorithme, je vais l'omettre ici.

Ainsi, le résultat de la mise en œuvre des trois lignes ci-dessus est Ligne 1: Split Ligne 2: Rejoindre Ligne 3: sortie Les rôles sont divisés comme ça.

Commençons par le «fractionnement».

Implémentation de "split"

Objectif

C'est le code en question.

Code "Split"


divide = lambda data: data if len(data) == 1 else [min(data), max(data)] if len(data) <= 2 else [divide([data[i] for i in range(len(data) // 2)]), divide([data[i] for i in range(len(data) // 2, len(data))])]

Si la séquence de données est «[7, 6, 3, 2, 4, 5, 1, 8]», le but du «fractionnement» provient de cette séquence.

[
    [
        [6, 7],
        [2, 3]
    ],
    [
        [4, 5],
        [1, 8]
    ],
]

Cela signifie qu'un tableau multiple avec une structure hiérarchique comme celle-ci sera généré. Divisez l'unité minimale en deux pour que le nombre d'éléments soit de 2 ou moins, et si le nombre d'éléments dans l'unité minimale est de 2 ou moins, classez-les par ordre croissant. Je fais quelque chose comme ça. Celles qui sont ordonnées par ordre croissant sont à l'origine le rôle de "couplage", mais il est pratique de le faire ici, donc je le ferai à ce stade.

Récrire

La fonction "split" est à l'origine comme ça.

Forme originale


def divide(data):
    if (len(data) <= 2):
        return data if len(data) == 1 else [min(data), max[data]]
    else:
        half_count = len(data) // 2
        left = [data[i] for i in range(half_count)]
        right = [data[i] for i in range(half_count, len(data))]
        return [divide(left), divide(right)]

Lorsque le nombre d'éléments est égal ou inférieur à 2, le tableau est renvoyé dans l'ordre croissant, et dans d'autres cas, la structure hiérarchique ci-dessus peut être réalisée en divisant en deux en gauche '' et droite '' et en reculant. Je vais.

Après ʻelse``, si vous utilisez la variable de half_count`` directement en la remplaçant par `len (data) // 2, vous pouvez éviter d'utiliser la variable. Oh, j'ai utilisé gauche '' et `` droite '' une seule fois! Si vous le faites tel quel dans le prix de retour

La valeur de retour est folle ~


def divide(data):
    if (len(data) <= 2):
        return data if len(data) == 1 else [min(data), max[data]]
    else:
        return [divide([data[i] for i in range(len(data) // 2)]), divide([data[i] for i in range(len(data) // 2, len(data))])]

Sera. Ah, «if» et «else» n'ont qu'une seule phrase «return». C ’est un opérateur ternaire et ce n’ est qu ’une ligne.

C'est une ligne avec un opérateur ternaire


def divide(data):
    return data if len(data) == 1 else [min(data), max(data)] if len(data) <= 2 else [divide([data[i] for i in range(len(data) // 2)]), divide([data[i] for i in range(len(data) // 2, len(data))])]

Cela se calme jusqu'à la sensation. S'il n'y a qu'un seul `` retour '' dans la fonction, utilisez une expression lambda

Faites-en un style lambda


divide = lambda data: data if len(data) == 1 else [min(data), max(data)] if len(data) <= 2 else [divide([data[i] for i in range(len(data) // 2)]), divide([data[i] for i in range(len(data) // 2, len(data))])]

Il s'intègre parfaitement dans une seule ligne. C'est bien de pouvoir utiliser la récurrence même dans les expressions lambda.

Implémentation de "join"

Objectif

C'est le code en question.

Code "Rejoindre"


merge = lambda left, right: [right.pop(0) if len(left) == 0 else left.pop(0) if len(right) == 0 else left.pop(0) if left[0] < right[0] else right.pop(0) for i in range(len(left) + len(right))] if type(left[0]) is int and type(right[0]) is int else merge(left, merge(right[0], right[1])) if type(left[0]) is int else (merge(merge(left[0], left[1]), right) if type(right[0]) is int else merge(merge(left[0], left[1]), merge(right[0], right[1])))

Guhe, Nageyo ... Le but de «rejoindre» est

Données après division


[
    [
        [6, 7],
        [2, 3]
    ],
    [
        [4, 5],
        [1, 8]
    ],
]

Il s'agit de combiner les données divisées dans l'ordre à partir de la couche inférieure, et enfin de les combiner toutes pour revenir à la forme originale d'une couche. Comme un flux

Flux 1


[
    [2, 3, 6, 7],
    [1, 4, 5, 8]
]

Flux 2


[1, 2, 3, 4, 5, 6, 7, 8]

Etc. Pour réaliser ce flux, la fonction `` fusion ''

--Les éléments gauche et droit de l'argument sont combinés lorsque leurs éléments enfants sont numériques

Je vais faire quelque chose comme ça. C'est difficile à comprendre même si vous l'expliquez avec des mots, alors regardons le code.

Récrire

La fonction "combiner" ressemble à l'origine à ceci.

Forme originale


def merge(left, right):
    if type(left[0]) is int and type(right[0]) is int: #Les deux lorsque l'élément enfant est un nombre
        result = [] #Préparez une nouvelle baie
        for i in range(len(left) + len(right)):
            # left,Lorsque le bon élément disparaît, faites apparaître celui qui existe encore
            if len(left) == 0:
                result.append(right.pop(0))
            elif len(right) == 0:
                result.append(left.pop(0))
            #S'il en reste les deux, éclatez le plus petit
            elif left[0] < right[0]:
                result.append(left.pop(0))
            else:
                result.append(right.pop(0))
        return result
    else:
        """ 
Selon la hiérarchie, les éléments enfants peuvent être des nombres ou des tableaux, même au même niveau.
Retraite avec l'élément enfant tel quel
        """
        if type(left[0]) is int:
            return merge(left, merge(right[0], right[1]))
        elif type(right[0]) is int:
            return merge(merge(left[0], left[1]), right)
        else:
            return merge(merge(left[0], left[1]), merge(right[0], right[1]))

Voir les commentaires pour les détails de mise en œuvre. Je l'ai fait intentionnellement avec «if-elif-else». Cela signifie que vous pouvez utiliser l'opérateur ternaire pour créer la valeur de retour sur une ligne, et vous pouvez également écrire la fonction sur une ligne avec une expression lambda, comme dans le cas de "split"!

Quand j'ai essayé d'exprimer le résultat '' en notation d'inclusion de liste, je craignais que pop '' réduise correctement les éléments, mais quand je l'ai essayé, il a diminué correctement. J'ai pu représenter la partie `` pour '' sur une ligne en utilisant la notation d'inclusion de liste et l'opérateur ternaire.

Mise en œuvre de la "sortie"

Code "Sortie"


print(merge(divide(data)[0], divide(data)[1]))

À l'origine ici

data = divide(data)
print(merge(data[0], data[1]))

Et `` divide '' ne doit être exécuté qu'une seule fois, mais comme vous pouvez le voir, c'est une perte du nombre de lignes à exercer 1 pour sécuriser la variable, donc je l'exécute de force deux fois. Eh bien, si le nombre d'éléments est d'environ 10, c'est une erreur.

fin

Je suis sûr que ce sera le code gagnant pour le Fucking Code of the Year Awards en moi. Merci beaucoup.

Recommended Posts

J'ai essayé d'implémenter le tri par fusion en Python avec le moins de lignes possible
J'ai essayé d'implémenter le tri sélectif en python
J'ai essayé d'implémenter PLSA en Python
J'ai essayé d'implémenter la permutation en Python
J'ai essayé d'implémenter PLSA dans Python 2
J'ai essayé d'implémenter ADALINE en Python
J'ai essayé d'implémenter PPO en Python
J'ai essayé d'implémenter TOPIC MODEL en Python
J'ai essayé d'implémenter Mine Sweeper sur un terminal avec python
J'ai essayé d'implémenter un pseudo pachislot en Python
J'ai essayé d'implémenter le poker de Drakue en Python
J'ai essayé d'implémenter le perceptron artificiel avec python
J'ai essayé d'implémenter GA (algorithme génétique) en Python
J'ai essayé d'implémenter un automate cellulaire unidimensionnel en Python
J'ai essayé d'implémenter la fonction d'envoi de courrier en Python
J'ai essayé de mettre en œuvre le chapeau de regroupement de Harry Potter avec CNN
J'ai essayé d'implémenter le blackjack du jeu Trump en Python
J'ai essayé d'implémenter Autoencoder avec TensorFlow
J'ai essayé de mettre en œuvre un jeu de dilemme de prisonnier mal compris en Python
J'ai essayé de savoir si ReDoS est possible avec Python
J'ai essayé d'implémenter CVAE avec PyTorch
J'ai essayé de mettre en œuvre une blockchain qui fonctionne réellement avec environ 170 lignes
J'ai essayé d'implémenter la régression linéaire bayésienne par échantillonnage de Gibbs en python
J'ai essayé d'implémenter le jeu de cartes de Trump en Python
J'ai essayé d'implémenter la lecture de Dataset avec PyTorch
J'ai essayé d'intégrer Keras dans TFv1.1
J'ai essayé d'obtenir des données CloudWatch avec Python
J'ai essayé de sortir LLVM IR avec Python
Je veux fusionner des dictionnaires imbriqués en Python
J'ai essayé d'automatiser la fabrication des sushis avec python
J'ai essayé d'expliquer à quoi sert le générateur Python aussi facilement que possible.
J'ai essayé d'implémenter ce qui semble être un outil de snipper Windows avec Python
J'ai essayé de représenter graphiquement les packages installés en Python
Je veux facilement implémenter le délai d'expiration en python
J'ai essayé d'implémenter et d'apprendre DCGAN avec PyTorch
J'ai essayé de démarrer avec le script python de blender_Part 01
J'ai essayé de toucher un fichier CSV avec Python
J'ai essayé de résoudre Soma Cube avec python
J'ai essayé de démarrer avec le script python de blender_Partie 02
J'étais accro au grattage avec Selenium (+ Python) en 2020
Je veux travailler avec un robot en python.
J'ai essayé de résumer comment utiliser les pandas de python
J'ai essayé de résoudre le problème avec Python Vol.1
J'ai essayé d'implémenter Grad-CAM avec keras et tensorflow
J'ai essayé d'implémenter SSD avec PyTorch maintenant (Dataset)
J'ai essayé de résoudre la théorie des nombres entiers d'AOJ avec Python
J'ai essayé fp-growth avec python
J'ai essayé de gratter avec Python
[Pour les professionnels de la compétition débutants] J'ai essayé de résoudre 40 questions AOJ "ITP I" avec python
J'ai essayé d'implémenter PCANet
J'ai essayé gRPC avec Python
J'ai essayé de gratter avec du python
J'ai essayé d'implémenter StarGAN (1)
J'ai essayé d'implémenter une ligne moyenne mobile de volume avec Quantx
J'ai essayé de trouver l'entropie de l'image avec python
J'ai essayé de simuler la propagation de l'infection avec Python
J'ai essayé de créer une API list.csv avec Python à partir de swagger.yaml