Opération de collecte de type Scala en Python

Background

L'opération de collecte de Scala est cool, n'est-ce pas? Vous pouvez écrire proprement sans créer de variables intermédiaires supplémentaires.

Scala


val result = (0 to 10000)
      .filter(_ % 3 == 0)
      .map(_ + 1)
      .groupBy(_ % 10)
      .map { it =>
        val k = it._1
        val v = it._2.sum
        (k, v)
    }.toList

Ce code est la somme de chaque nombre lorsque les nombres de 0 à 10000 sont laissés sous forme de multiple de 3 et divisés par 1 et divisés en groupes. Ce calcul n'a pas de signification particulière, mais c'est un exemple dans lequel le flux de traitement des données peut être écrit d'une manière très facile à comprendre (cool) avec exactement le même ordre de pensée.

Quand j'essaye de faire ça en Python ...

Python


import itertools
result = range(0, 10001)
result = filter(lambda x: x % 3 == 0, result)
result = map(lambda x: x + 1, result)
result = map(lambda x: (x % 10, x), result)
result = sorted(result)
result = itertools.groupby(result, lambda x: x[0])
result = map(lambda x: (x[0], sum(map(lambda _: _[1], x[1]))), result)
result = list(result)

C'est difficile à voir et je ne peux même pas le voir. Au fait, si vous écrivez d'un seul coup sans utiliser de variables intermédiaires

Python


result = list(
    map(lambda x: (x[0], sum(map(lambda _: _[1], x[1]))),
        itertools.groupby(
            sorted(
                map(lambda x: (x % 10, x),
                    map(lambda x: x + 1,
                        filter(lambda x: x % 3 == 0,
                               range(0, 100001)
                        )
                    )
                ), lambda x: x[0]
            )
        )               
    )
)

Le code avec une lisibilité 0 est terminé. Vous pouvez vous réveiller à quelque chose lorsque vous pouvez lire ceci en douceur. La raison en est que si vous voulez traiter dans l'ordre f-> g-> h, vous devez écrire dans l'ordre inverse comme h (g (f (x))).

En fait, il existe une bibliothèque qui résout ce problème. Oui, avec toolz, scalafunctional et fn.py. Dans cet article, des opinions telles que ** Ecrire en Scala ** sont des mots NG.

Toolz, CyToolz

toolz est une bibliothèque qui étend les ʻitertools et functools intégrés à Python afin qu'ils puissent être écrits de manière plus fonctionnelle. cytoolz est également une version plus rapide de celui-ci recréée en Cython. Les fonctions «pipe» et curled implémentées dans ces derniers sont très utiles. Le terrible code ci-dessus peut être écrit comme suit:

from cytoolz.curried import *
import operator as O
result = pipe(range(0, 10001),
    filter(lambda x: x % 3 == 0),
    map(lambda x: x + 1),
    reduceby(lambda x: x % 10, O.add),
    lambda d: d.items(),
    list
)

Comment c'est? Donnez les données que vous souhaitez traiter avec le premier argument et indiquez les fonctions que vous souhaitez appliquer avec le deuxième argument et les suivants les uns après les autres. Si vous êtes familier avec le langage R, vous pouvez penser à dplyr. Au fait, le filtre, map et reductionby utilisés ici sont tous curry, donc map (f, data) ʻest multipliée comme map (f) (data). Vous pouvez vous connecter avec pipecomme ceci. Si vous n'utilisez pas la version recourbée, remplacezpipe par thread_last` et les données traitées par la fonction précédente seront passées au dernier argument de chaque fonction l'une après l'autre.

ScalaFunctional

Comme son nom l'indique, scalafunctional est une bibliothèque qui vous permet d'exploiter la collection Scala comme. ~~ Si vous voulez aller aussi loin, ajoutez Scala (ry ~~ Dans cette bibliothèque, mettez list, dict, etc. dans une classe dédiée appelée seq et traitez-la dans une chaîne de points.

from functional import seq
result = seq(range(0, 10001)) \
    .filter(lambda x: x % 3 == 0) \
    .map(lambda x: x + 1) \
    .map(lambda x: (x % 10, x)) \
    .reduce_by_key(O.add) \
    .to_list()

C'est le plus proche de Scala. Cependant, Python nécessite une barre oblique inverse à la fin de la ligne, ce qui est un peu ennuyeux. Après cela, l'expression «lambda» de Python n'est pas aussi flexible que la fonction de Scala, il peut donc être nécessaire de «déf» la fonction une fois pour un traitement compliqué. Quoi qu'il en soit, c'est très simple et beau.

fn.py

fn.py est également une bibliothèque pour la programmation fonctionnelle Python. La plus grande caractéristique est qu'il peut être écrit comme un espace réservé Scala.

from fn import _
result = map(_ + 1, range(10))

Vous pouvez simplement l'utiliser à la place de lambda.

f = _ + 1
f(10)

>>>
11

Cela va bien avec toolz et scalafunctional.

toolz


result = pipe(range(10),
    map(_ + 1),
    list
)

scalafunctional


result = seq(range(10)) \
    .map(_ + 1) \
    .to_list()

Au fait, dans IPython etc., _ semble être après réservation pour représenter la dernière sortie, donc lors de son utilisation là-bas, il est nécessaire de ʻimport` avec un autre nom.

from fn import _ as it

Résumé

Si vous utilisez toolz et scalafunctional, la programmation fonctionnelle sera améliorée même en Python. scalafunctional peut être écrit exactement comme l'opération de collecte de Scala. D'autre part, vous pouvez utiliser pipe of toolz pour écrire non seulement des opérations de collecte, mais aussi un flux de traitement de données plus polyvalent. Veuillez bien les combiner avec fn.py et profiter de la vie fonctionnelle de Python [^ pandas].

Toutes les bibliothèques utilisées cette fois sont publiées sur GitHub. Bien sûr, il est également enregistré dans PyPI, vous pouvez donc l'installer avec pip.

[^ pandas]: Même les Pandas standard peuvent être connectés à DataFrame par chaîne de points dans une certaine mesure.

Recommended Posts

Opération de collecte de type Scala en Python
Opérations sur les fichiers en Python
Manipulation de fichiers avec Python
Quatre règles de python
Encapsulation des opérations git en Python
Collection de traitement d'image en Python
ORC, opérations de fichier Parquet en Python
Générer une collection de première classe en Python
Programmation scientifique Collection Petit Tech en Python
[Python] Comprendre le fonctionnement des tranches de liste en quelques secondes
Quadtree en Python --2
CURL en Python
Métaprogrammation avec Python
Python 3.3 avec Anaconda
Géocodage en python
SendKeys en Python
Méta-analyse en Python
Unittest en Python
Époque en Python
Discord en Python
Allemand en Python
DCI en Python
tri rapide en python
nCr en python
N-Gram en Python
Programmation avec Python
Plink en Python
Constante en Python
FizzBuzz en Python
Sqlite en Python
Étape AIC en Python
LINE-Bot [0] en Python
CSV en Python
Assemblage inversé avec Python
Réflexion en Python
Constante en Python
nCr en Python.
format en python
Scons en Python 3
Puyopuyo en python
python dans virtualenv
PPAP en Python
Quad-tree en Python
Réflexion en Python
Chimie avec Python
Hashable en Python
DirectLiNGAM en Python
LiNGAM en Python
Aplatir en Python
Aplatir en python
Effectuer une analyse d'entité à l'aide de spaCy / GiNZA en Python
Résumé des opérations Excel utilisant OpenPyXL en Python
Liste triée en Python
AtCoder # 36 quotidien avec Python
Texte de cluster en Python
AtCoder # 2 tous les jours avec Python
Daily AtCoder # 32 en Python