3
votes

Recherche du nombre le plus bas sur 10 dans une liste imbriquée / plate de chaînes et d'entiers

J'essaie d'extraire le nombre le plus bas sur 10 à partir d'une liste de chaînes et d'entiers imbriqués et non imbriqués pour chaque élément. J'ai essayé plusieurs choses différentes, mais elles ne renvoient rien ou quelques messages d'erreur différents (la chaîne ou le tampon attendu, '>' pas possible entre int et list étaient deux d'entre eux). Ils doivent rester en ordre car ils seront ensuite entrés dans une trame de données pandas.

def min_int(data):
    for item in range(len(data)):
        for i in range(len(data[item])):
            if type(data[item][i]) == int:
                if data[item][i] >10:
                    data.remove(data[item][i])
            else:
                data[item][i] =int(re.sub(r'\D', "", data[item]))
                if data[item][i] >10:
                    data.remove(data[item][i])
        data[item] = min(data)

def remove_text(data):
    for i in range(len(data)):
        try:
            for ii in range(len(data[i])):
                try:
                    data[i][ii] =int(re.sub(r'\D', "", data[item]))
                except:
                    continue
        except:
            continue 

Voici 2 des différentes fonctions que j'ai essayées. Parce que les résultats vont dans une trame de données, une réponse basée sur les pandas conviendrait également.

starting_list = [['4dfg', '12kfmgfg','dfgdf133'],[8, '16dgdfg'], 11, '', 'fdsf']

desired_result = [12, 16, 11, NaN, NaN]

Merci!


2 commentaires

Veuillez expliquer, en termes simples anglais, la logique qui vous amène de l'entrée spécifiée à la sortie souhaitée. Incluez chaque étape du processus que vous suivriez, lorsque vous effectuez le calcul à la main. Il semble, par exemple, qu'il y ait au moins trois cas où l'on considère l'un des éléments de starting_list : il peut s'agir d'un entier, d'une chaîne ou d'une liste. Aucun des codes que vous montrez ne semble tenter de considérer les trois possibilités à la fois.


Vous devriez essayer d'écrire une fonction qui vous donne le résultat correct pour un seul élément de starting_list , puis l'utiliser pour obtenir le résultat global.


3 Réponses :


0
votes

Utilisation:

def try_to_int(x):
    try:
        return int(re.sub(r'\D', "", x))
    except:
        return np.nan

def min_int(x):
    if isinstance(x, int):
        return x
    elif isinstance(x, list):
        gen = (try_to_int(y) for y in x)
        return min(y for y in gen if y == y and y > 10)
    else:
        return try_to_int(x)
        

print ([min_int(x) for x in starting_list])
[12, 16, 11, nan, nan]
    

Votre fonction doit être simplifiée:

s = pd.Series(data)
a = (pd.to_numeric(s.explode() #explode lists
                     .astype(str) #convert all values to strings
                     .str.replace(r'\D', ''), errors='coerce') #replace and convert to numbers if possible
                     .loc[lambda x: x > 10] #filter values
                     .min(level=0) #get minimal per index
                     .reindex(s.index) #add removed values of index
                     .tolist()) #convert to list

#convert non NaNs to integers
a = [int(x) if x == x else x for x in a]
print (a)
[12, 16, 11, nan, nan]


0 commentaires

0
votes

Bien que vous ayez déjà une réponse acceptée par pandas-wiz @jezrael, voici une approche de niveau inférieur, si vous le souhaitez.

Essentiellement, il utilise regex pour extraire les valeurs numériques et des filtres pour répondre à vos besoins, puis les ajoute à une liste de sortie.

list_ = [['4dfg', '12kfmgfg', 'dfgdf133'],
         [8, '16dgdfg'],
         11,
         '',
         'fdsf']

Production:

>>> [12, 16, 11, nan, nan]

Installer:

import re

exp = re.compile(r'(\d+)')

new = []
for i in list_:
    if isinstance(i, list):
        new2 = []
        for j in i:
            f = exp.findall(str(j))
            new2.append(int(f[0]) if f else float('nan'))
        new.append(min(i for i in new2 if i > 10))
    else:
        f = exp.findall(str(i))
        new.append(int(f[0]) if f else float('nan'))


0 commentaires

-1
votes

Vous pouvez créer un générateur:

12
133
16
11
nan
nan

Le tester:

>>> desired_result = select_numbers(starting_list)      # re-creating exhausted generator
>>>
>>> for elem in desired_result:                         # direct use of generator in loop
>>>     print(elem)
[12, 133, 16, 11, nan, nan]
>>> starting_list = [['4dfg', '12kfmgfg','dfgdf133'],[8, '16dgdfg'], 11, '', 'fdsf']
>>>
>>> desired_result = select_numbers(starting_list)       # generator, not a list
>>> list(desired_result)
from collections.abc import Iterable
import re


def select_numbers(items, limit=10):
    for item in items:
        if isinstance(item, Iterable) and not isinstance(item, str):
            yield from select_numbers(item, limit)
        else:
            item = re.sub(r"\D", "", str(item))
            if item == "":
                yield float("NaN")
            elif int(item) > limit:
                yield int(item)
                 


4 commentaires

Conformément aux exigences de l'OP, 133 ne doit pas être répertorié dans la sortie.


@ S3DEV, je ne vois pas une telle exigence, ni dans la question OP, ni dans leur commentaire.


"J'essaie d'extraire le nombre le plus bas sur 10 ..." et le résultat desired_result = [12, 16, 11, NaN, NaN]


@ S3DEV, vous avez probablement raison. Spécification pas très claire pour moi, et pas seulement pour moi - voir le premier commentaire sous la question.