Извлечение и округление чисел из списка строк в Python - PullRequest
1 голос
/ 03 ноября 2019

У меня есть список Python, который содержит строки, целые числа и числа с плавающей запятой

my_list = [['100', '200.1', 'z', '300.9', '400', '100.2']]

Я пытался выяснить, как:

  • удалить строки
  • округлить до числа и преобразовать их в целые числа
  • удалить дубликаты

Цель состоит в том, чтобы вернуть список, похожий на список ниже

new_list = [100, 200, 301, 400]

Возможно ли это и как мне подойти к этому?

Ответы [ 10 ]

1 голос
/ 03 ноября 2019

Самый безопасный способ удаления буквенно-цифровых символов и преобразования остальных в округленное int выглядит примерно так:

import re

my_list = [['100', '200.1', 'z', '1000_100', '300.9', '400', '100.2']]
my_list_2 = list(set([round(float(x)) for x in my_list[0] if re.fullmatch("[\d\.]+",x) is not None]))
print(my_list_2)

[200, 400, 100, 301]

Гораздо лучший ответ благодаря Александру и Стефану.

0 голосов
/ 06 ноября 2019

Другой подход: используйте more-itertools .

from more-itertools import map_except, unique_everseen
my_list = ['100', '200.1', 'z', '300.9', '400', '100.2']

intlist = list(unique_everseen(map_except(lambda s: round(float(s)), my_list, ValueError)))
##########################################################################################

print(intlist) #> [100, 200, 301, 400]

Вот документы

0 голосов
/ 04 ноября 2019

Это один вкладыш

list(dict.fromkeys(x for x in (round_or_none(s) for s in l) if x))

(если, конечно, вы заранее определили функцию round_or_none,

def round_or_none(s):
    try:
        return round(float(s))
    except ValueError:
        pass

, то есть: -)

Демо:

>>> def round_or_none(s):
...     try:
...         return round(float(s))
...     except ValueError:
...         pass
... 
>>> l = ['100', '200.1', 'z', '300.9', '400', '100.2']
>>> list(dict.fromkeys(x for x in (round_or_none(s) for s in l) if x))
[100, 200, 301, 400]
>>>

Без дополнительной функции

rounded = []
for s in l:
    try:
         rounded.append(round(float(s)))
    except ValueError:
         pass
rounded = list(dict.fromkeys(rounded))

Это работает для Python 3.6 и новее, в противном случае используйте OrderedDict

from collections import OrderedDict
...
rounded = list(OrderedDict.fromkeys(rounded))
0 голосов
/ 03 ноября 2019

Формат списка четко не определен. Ради этого решения я буду предполагать, что ввод представляет собой двумерный список строк (AKA - список списка строк). Если ваши списки имеют другой формат (несколько уровней, подсписки смешаны со строками и т. Д.), Возможно, списки - это не та структура данных, которая вам нужна.

import itertools as itt

def str_to_int(str_in):
    try:
        res = round(float(str_in))
    except ValueError:
        res = None
    return res

def trans_lst(lst_in):
    flat_lst = itt.chain.from_iterable(lst_in)
    parse_res = (str_to_int(item) for item in flat_lst)
    res_lst = list(set((item for item in parse_res if item is not None)))

    return res_lst
0 голосов
/ 03 ноября 2019

Самый простой способ - создать вспомогательную функцию, которая позволит вам конвертировать в целое число без броска:

my_list = [['100', '200.1', 'z', '300.9', '400', '100.2']]

def make_int(s):
    """
    Convert s to an int, rounding if it is a floating point value. 
    Return None if the conversion cannot be done.
    """

    try:
        return int(round(float(s)))
    except:
        return None

newlist = list(set([i for i in [make_int(s) for s in my_list[0]] if i != None]))

Это включает в себя два понимания вложенного списка:

Внутренняя конвертирует список вокругленные числа с плавающей запятой, возвращающие None для строк: [make_int(s) for s in my_list[0]]

Внешняя строка удаляет None 's: [i for i in <inner> if i != None]

Это также устраняет необходимость отбрасывать выражения регулярными выражениями.

0 голосов
/ 03 ноября 2019

ммм, чтобы решить эту проблему, я бы использовал пару трюков и список пониманий.

#with a regex you can define a matching pattern in order to
#clean the list of strings of every alpabetic element

import re
old = ['100', '200.1', 'z', '300.9', '400', '100.2']

# for every element that not match with capitals A to Z, or a to z
# make it a round float into this list.
new = [round(float(x)) for x in old if not re.match(r'[A-Za-z]',x)]
#clean the duplicates and print
print(list(set(new)))
0 голосов
/ 03 ноября 2019

Простой ответ

my_list = [['100', '200.1', 'z', '300.9', '400', '100.2']]
new_list=[]
for i in my_list:
    for j in i:
        try:
            num=round(float(j))
            if num not in new_list:
                new_list.append(num)
        except:
            pass
print(new_list)
0 голосов
/ 03 ноября 2019

Обратите внимание, что у вашего вопроса есть список, содержащий список строк.

Если у вас действительно есть список строк, пропустите [0].

result = []
for item in my_list[0]:
  try:
    v = float(item)
  except ValueError:
    continue
  v = int(round(v))

  if v not in result:
    result.append(v)

Тогда

print(result)
[100, 200, 301, 400]
0 голосов
/ 03 ноября 2019

"питонический" однострочный:

a = ['100', '200.1', 'z', '300.9', '400', '100.2']
list(set([int(round(float(b))) for b in a if b.isdigit()]))
>>> [400, 100]
0 голосов
/ 03 ноября 2019

Самый простой способ - использовать "try / catch" и просто построить из него новый список.

my_list = ['100', '200.1', 'z', '300.9', '400', '100.2']
new_list = []
for item in my_list:
    try:
        new_list.append(int(float(item)))
    except ValueError:
        pass

new_list = list(set(new_list))
print(new_list)

Альтернативой является использование понимания списка. Используйте round вместо int, если вы хотите округление, а не усечение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...