0

I have a Python script that reads in a .csv file and stores each of the values into a list of lists: list[x][y]. I don't have any issues with this.

list = []
i = 0

for row in reader:
     list.append([])
     list[i].append(row[0])
     ...
     i += 1

I want to check one of these fields to see if it's an number (integer).

When I perform a print type(list[i][0]) it returns a <type 'str'> even though the value is say 100.

The if statements below are in a for loop iterating through the lists so what I was thinking of doing is doing a check:

if type(list[i][0] == types.IntType):
     True
else: 
     False

This works, however that's frowned upon in PEP8 and so I should be using isinstance(), therefore I have modified it to

# check if a value is entered
if list[i][0] != '':
    if isinstance(int(list[i][0]), int):
        True
    else: 
        False
else
    False 

But I run into the problem of trying to convert a string to an int (if the user enters a string).

How do I overcome this? It seems like a simple issue however I am new to Python so I was wondering of a neat and efficient way of dealing with this. Should I be checking if the value is an int before storing it into the list?

I am using Python2.

Thanks

edit: I have wrapped the isinstance() check around a try exception catch however I feel like I shouldn't have to resort to this just to check if something is an int or not? Just curious if there was a neater way to do this.

edit: I have used isdigit as mentioned previously however I was getting negative results.

i.e. given this data set. list[0][0] = 123, list[1][0] = asdasd

for i in range(0, 1):
   if (list[i][0]).isdigit:
       tempInt = list[i][0]
       print type(tempInt)
       print 'True: ' + tempInt
   else: 
       tempInt = 1
       print 'False: ' + tempInt

Results:

<type 'str'>
True: 123
<type 'str'>
True: asdasd
Brendan
  • 908
  • 2
  • 15
  • 30
  • I think the duplicate is wrong. Pretty sure he wants to convert `"123"` to `123` which is done by `somestring.isdigit` to check or `int(somestring)` to convert. – Reut Sharabani Jul 21 '16 at 06:59
  • @ReutSharabani Yes you are correct, that duplicate question does not relate to my issue – Brendan Jul 21 '16 at 07:01
  • I recommend reading through that question's answers. You'll find [one that specifically mentions `isdigit()`](http://stackoverflow.com/a/23464130/2617068). – TigerhawkT3 Jul 21 '16 at 07:02
  • I think there are better duplicates since the duplicate's question is different, even if the answer is the same. What about this: http://stackoverflow.com/questions/379906/parse-string-to-float-or-int?noredirect=1&lq=1 ? – Reut Sharabani Jul 21 '16 at 07:03
  • 2
    There could be any number of duplicates, most of which can be found by Googling this question's exact title... – TigerhawkT3 Jul 21 '16 at 07:03
  • Thanks for the replies. While I do have a solution of catching an exception I was wondering if there was a cleaner way of checking if a value is an int. I am parsing nearly a million values through multiple .csv files so I feel this would be inefficient, hence the question. My question, I guess, specifically relates to appending values from a file to a list. Maybe I should have explicitly stated that in my original question. – Brendan Jul 21 '16 at 07:09
  • @Brendan: I think you're a bit confused about Python types. If you're reading something from a file, it's *never* going to be an `int` or any other numeric type. It will always be a string. Now, some of the strings may *represent* numbers, but that's a different thing than *being* a number already. Unlike some other languages (e.g. Javascript), Python don't ever convert from strings to numbers automatically. – Blckknght Jul 21 '16 at 07:20
  • @Blckknght I have tried using `isdigit` previously however it was giving false-negative results. I have fed it strings and it still returns true. I will update my original post. – Brendan Jul 21 '16 at 07:24
  • 1
    You need to call isdigit, not just reference it: `list[i][0].isdigit()`. The bound method you were getting when you didn't include the call would always be truthy. – Blckknght Jul 21 '16 at 07:37
  • @Blckknght Thank you! – Brendan Jul 21 '16 at 07:44

2 Answers2

1

You can check it with this - this is for all numbers (positive and negative integer, floats, Nan), for only int or certain subclass, better approaches might exist.

def is_number(a):
    # will be True also for 'NaN'
    try:
        number = float(a)
        return True
    except ValueError:
        return False

At face-value, it does not look good. But I think this is probably the best way if you want to consider all number (negative, float, integer, infinity etc), you can see a highly view/voted question/answer here. Also note that isdigit does not work in all cases.

Community
  • 1
  • 1
DurgaDatta
  • 3,952
  • 4
  • 27
  • 34
  • Thanks, I forgot to add that to my post. Yes I did consider that which works but although I consider it a bit crude having to catch an exception just to check if a value is an int or not. – Brendan Jul 21 '16 at 07:02
  • This answer is incorrect. It will mistakenly accept values like `1.2`, which are not integers as the OP wants. Why are you using `float()`? – TigerhawkT3 Jul 21 '16 at 07:03
  • I saw `int/number` in the title. I think OP wants to consider all the numbers in mathematical sense. – DurgaDatta Jul 21 '16 at 07:06
  • All the examples, sample code, and problem description also exclusively mention integers and not floating-point numbers. – TigerhawkT3 Jul 21 '16 at 07:08
  • I have added a note. May be I did not understand it correctly. – DurgaDatta Jul 21 '16 at 07:14
  • It's still wrong. There is literally nothing in the question about floats. Everything points to integers. For all we know, it may be a number of people or something, for which floats make zero sense. You don't even mention the possibility of integers - in fact, you specifically degrade `isdigit()` as being inappropriate. I don't understand why an incorrect answer on a duplicate question is being upvoted... – TigerhawkT3 Jul 21 '16 at 07:18
0

The following approach will return for integers only:

string_list = ['20.0', '100', 'abc', '10.3445', 'adsfasdf.adsfasdf', '10,3445', '34,0']

def check(inp):
    try:
        inp = inp.replace(',', '.')
        num_float = float(inp)
        num_int = int(num_float)
        return num_int == num_float
    except ValueError:
        return False

print([check(s) for s in string_list])

Giving:

[True, True, False, False, False, False, True]

The trick is to cast the string to a float first and convert that into an integer (which will round the float if decimal part is not zero). After that you can compare the integer- and float-representation of the input in order to find out if the input was an integer or not. I added .replace() in order to support both european and american/english decimal notation using commas.

albert
  • 8,027
  • 10
  • 48
  • 84