How to check for numeric values in list of lists and return multiple lists?

Viewed 79

I have a list of lists as shown below, my goal is to get the numeric values from it. But the resultant output should be in similar format as of original list. so for example my list looks like this:

a_list = [['49', 'XT', '19.0', '93'],
 ['YTX', '124.0', '167 ', '77.0'],
 ['4 ', 'Y', '128,', '125,'],
 ['142.0', '120', '141.0'],
 ['12 ', '51.0'],
 ['0,', ' 82', '156'],
 ['82', '102.0'],
 ['94', 'YYZ', '178.0', '72'],
 ['120', 'YXT', '142', ' 134'],
 ['45,', '46', '79.0']]

My desired output is

b_list = [['49', '19.0', '93'],
 ['124.0', '167 ', '77.0'],
 ['4 ', '128,', '125,'],
 ['142.0', '120', '141.0'],
 ['12 ', '51.0'],
 ['0,', ' 82', '156'],
 ['82', '102.0'],
 ['94', '178.0', '72'],
 ['120', '142', ' 134'],
 ['45,', '46', '79.0']]

I wrote following code but it skips a lot of numbers plus format is not the same

final=[]
for i in a_list:
    for num in i:
        if num.isdigit():
            final.append(num)

what I am doing wrong? and any way it could be done using list comprehension?

5 Answers

a simple regex solition:

import re
isnum = re.compile(r'\d+(\.\d+)?$')

final=[]
for i in a_list:
    tmp =[]
    for num in i:
        num = num.strip().replace(",","")
        if isnum.match(num):
            tmp.append(num)
    final.append(tmp)

Try this:

final=[]
for i in a_list:
    for num in i:
        tmp=[]
        if num.isdigit():
            tmp.append(num)
    final.append(tmp)

Your input list sometimes contains characters that will fail the is.decimal check. Define a filtering method and pass it to the filter builtin.

def _method(x):
    y = x.strip().replace('.', '').replace(',', '')
    return y.isdecimal()

result = [list(filter(_method, x)) for x in a_list]

There exists a small catch when it comes to str.isidigit method, for example it will acccept characters like "³" and these cannot be passed as an index to Indexable objects. str.isdecimal is stricter and as far as I know everything that passes through str.isdecimal can be used as an index:

>>> a = '³'
>>> a.isdigit()
True
>>> a.isdecimal()
False

Here is one solution I got:

b_list = []
for i in a_list:
    new_list = []
    for j in i:
        if j.replace(".", "", 1).replace(" ", "", 1).replace(",", "", 1).isdigit():
            new_list.append(j)
    b_list.append(new_list)
b_list

The output is same as your desired output:

[['49', '19.0', '93'],
 ['124.0', '167 ', '77.0'],
 ['4 ', '128,', '125,'],
 ['142.0', '120', '141.0'],
 ['12 ', '51.0'],
 ['0,', ' 82', '156'],
 ['82', '102.0'],
 ['94', '178.0', '72'],
 ['120', '142', ' 134'],
 ['45,', '46', '79.0']]

This is a rather old thread, but I have found myself in the same situation and I would like to leave here the solution I have implemented.

Given the desired output, you just can make use of the regex funcion search(), and find whichever element that contains a digit re.compile('\d'). This way you avoid issues related to last-index commas and whitespaces: These elements won't be considered as digits when you use .isdigit()

It should be noted that if you had alphanumeric elements in your lists this solution would not be appropriate. However, as you propose it, it meets your needs completely:

The code would look like this:

import re

output = []
for list in a_list:
    temp=[]
    for x in list:
        if re.compile('\d').search(x):
            temp.append(x)
    output.append(temp)

Further elaborating on the answer provided so far. We can make use of list comprehensions for a more concise and tidy code. Perhaps at the expense of some readability:

import re

[[x for x in a_list[i] if re.compile('\d').search(x)] for i in range(len(a_list))]
Related