How to convert list of intable strings to int - python

In Python, I want to convert a list of strings:
l = ['sam','1','dad','21']
and convert the integers to integer types like this:
t = ['sam',1,'dad',21]
I tried:
t = [map(int, x) for x in l]
but is showing an error.
How could I convert all intable strings in a list to int, leaving other elements as strings?
My list might be multi-dimensional. A method which works for a generic list would be preferable:
l=[['aa','2'],['bb','3']]

I'd use a custom function:
def try_int(x):
try:
return int(x)
except ValueError:
return x
Example:
>>> [try_int(x) for x in ['sam', '1', 'dad', '21']]
['sam', 1, 'dad', 21]
Edit: If you need to apply the above to a list of lists, why didn't you converted those strings to int while building the nested list?
Anyway, if you need to, it's just a matter of choice on how to iterate over such nested list and apply the method above.
One way for doing that, might be:
>>> list_of_lists = [['aa', '2'], ['bb', '3']]
>>> [[try_int(x) for x in lst] for lst in list_of_lists]
[['aa', 2], ['bb', 3]]
You can obviusly reassign that to list_of_lists:
>>> list_of_lists = [[try_int(x) for x in lst] for lst in list_of_lists]

How about using map and lambda
>>> map(lambda x:int(x) if x.isdigit() else x,['sam','1','dad','21'])
['sam', 1, 'dad', 21]
or with List comprehension
>>> [int(x) if x.isdigit() else x for x in ['sam','1','dad','21']]
['sam', 1, 'dad', 21]
>>>
As mentioned in the comment, as isdigit may not capture negative numbers, here is a refined condition to handle it notable a string is a number if its alphanumeric and not a alphabet :-)
>>> [int(x) if x.isalnum() and not x.isalpha() else x for x in ['sam','1','dad','21']]
['sam', 1, 'dad', 21]

I would create a generator to do it:
def intify(lst):
for i in lst:
try:
i = int(i)
except ValueError:
pass
yield i
lst = ['sam','1','dad','21']
intified_list = list(intify(lst))
# or if you want to modify an existing list
# lst[:] = intify(lst)
If you want this to work on a list of lists, just:
new_list_of_lists = map(list, map(intify, list_of_lists))

For multidimenson lists, use recursive technique may help.
from collections import Iterable
def intify(maybeLst):
try:
return int(maybeLst)
except:
if isinstance(maybeLst, Iterable) and not isinstance(lst, str):
return [intify(i) for i in maybeLst] # here we call intify itself!
else:
return maybeLst
maybeLst = [[['sam', 2],'1'],['dad','21']]
print intify(maybeLst)

Use isdigit() to check each character in the string to see if it is a digit.
Example:
mylist = ['foo', '3', 'bar', '9']
t = [ int(item) if item.isdigit() else item for item in mylist ]
print(t)

Use a list comprehension to validate the numeracy of each list item.
str.isnumeric won't pass a negative sign
Use str.lstrip to remove the -, check .isnumeric, and convert to int if it is.
Alternatively, use str.isdigit in place of .isnumeric.
Keep all values in the list
l = ['sam', '1', 'dad', '21', '-10']
t = [int(v) if v.lstrip('-').isnumeric() else v for v in l]
print(t)
>>> ['sam', 1, 'dad', 21, -10]
Remove non-numeric values
l = ['sam', '1', 'dad', '21', '-10']
t = [int(v) for v in t if v.lstrip('-').isnumeric()]
print(t)
>>> [1, 21, -10]
Nested list
l = [['aa', '2'], ['bb', '3'], ['sam', '1', 'dad', '21', '-10']]
t = [[int(v) if v.lstrip('-').isnumeric() else v for v in x] for x in l]
print(t)
>>> [['aa', 2], ['bb', 3], ['sam', 1, 'dad', 21, -10]]

Related

Removing strings from a list dependent on their length?

I am trying to remove any strings from this list of strings if their length is greater than 5. I don't know why it is only removing what seems to be random strings. Please help. The item for sublist part of the code just changes the list of lists, into a normal list of strings.
list2 = [['name'],['number'],['continue'],['stop'],['signify'],['tester'],['racer'],['stopping']]
li = [item for sublist in list2 for item in sublist]
var=0
for words in li:
if len(li[var])>5:
li.pop()
var+=1
print(li)
The output is: ['name', 'number', 'continue', 'stop', 'signify']
Just include the check when flattening the list:
list2 = [['name'],['number'],['continue'],['stop'],['signify'],['tester'],['racer'],['stopping']]
li = [item for sublist in list2 for item in sublist if len(item) <= 5]
['name', 'stop', 'racer']
You can use a list comprehension to build a new list with only items that are 5 or less in length.
>>> l = ['123456', '123', '12345', '1', '1234567', '12', '1234567']
>>> l = [x for x in l if len(x) <= 5]
>>> l
['123', '12345', '1', '12']
list(filter(lambda x: len(x[0]) <= 5, list2))

Flatten lists of variable depths in Python

I have a list of n lists. Each internal list contains a combination of (a) strings, (b) the empty list, or (c) a list containing one string. I would like to transform the inside lists so they only contain the strings.
I have a list like this for example:
[[[],["a"],"a"],[["ab"],[],"abc"]]
and I would like it to be like this:
[["","a","a"],["ab","","abc"]]
I know I could probably go through with a loop but I am looking for a more elegant solution, preferably with a list comprehension.
List comprehension:
>>> original = [[[],["a"],"a"],[["ab"],[],"abc"]]
>>> result = [['' if not item else ''.join(item) for item in sublist] for sublist in original]
>>> result
[['', 'a', 'a'], ['ab', '', 'abc']]
As every element of the list that you'd like to flatten is iterable, instead of checking of being instance of some class (list, string) you can actually make use of duck-typing:
>> my_list = [[[],["a"],"a"],[["ab"],[],"abc"]]
>> [list(map(lambda x: ''.join(x), elem)) for elem in my_list]
Or more readable version:
result = []
for elem in my_list:
flatten = map(lambda x: ''.join(x), elem)
result.append(list(flatten))
Result:
[['', 'a', 'a'], ['ab', '', 'abc']]
It's quite pythonic to not to check what something is but rather leverage transformation mechanics to adaptive abilities of each of the structure.
Via list comprehension:
lst = [[[],["a"],"a"],[["ab"],[],"abc"]]
result = [ ['' if not v else (v[0] if isinstance(v, list) else v) for v in sub_l]
for sub_l in lst ]
print(result)
The output:
[['', 'a', 'a'], ['ab', '', 'abc']]
original_list = [[[],["a"],"a"],[["ab"],[],"abc"]]
flatten = lambda x: "" if x == [] else x[0] if isinstance(x, list) else x
flattened_list = [[flatten(i) for i in j] for j in original_list]

Grouping two lists of lists in Python based on value

I have two lists in Python.
list1 = ['a','a','b','a','c','b','c','a','d','a','b']
list2 = ['1','2','21','12','1','32','11','12','21','3','31']
I have to group the similar elements in list1. The corresponding elements in list2 should also get grouped based on this. Output should be this:
list1 = [['a','a','a','a','a'],['b','b','b'],['c','c'],['d']]
list2 = [['1','2','12','12','3'],['21','32','31'],['1','11'],['21']]
What is the best way to do this?
If you do not care about the order of elements in the first list, you may use defaultdict:
In [7]: from collections import defaultdict
In [8]: from itertools import izip
In [9]: res = defaultdict(list)
In [10]: for k, v in izip(list1, list2):
....: res[k].append(v)
....:
In [11]: print(res)
defaultdict(<type 'list'>, {'a': ['1', '2', '12', '12', '3'], 'c': ['1', '11'], 'b': ['21', '32', '31'], 'd': ['21']})
In [12]: res.items()
Out[12]:
[('a', ['1', '2', '12', '12', '3']),
('c', ['1', '11']),
('b', ['21', '32', '31']),
('d', ['21'])]
This code worked for me:
groups = list(set(list1))
list1_tmp, list2_tmp = [], []
for char in groups:
list1_tmp.append([])
list2_tmp.append([])
for i in range(len(list1)):
list1_tmp[groups.index(list1[i])].append(list1[i])
list2_tmp[groups.index(list1[i])].append(list2[i])
list1 = list1_tmp
list2 = list2_tmp
The output should be valid as well for any other similar input.
This code should do it:
final_list1 = []
final_list2 = []
for distinct in sorted(list(set(list1))):
index = 0
distinct_list1 = []
distinct_list2 = []
for element in list1:
if element == distinct:
distinct_list1.append(element)
distinct_list2.append(list2[index])
index += 1
final_list1.append(distinct_list1)
final_list2.append(distinct_list2)
list1 = final_list1
list2 = final_list2
This will give you exactly the output you asked for. If you don't really care about the output, there are probably better ways as #soon proposed.
Here's a (kind of ugly) implementation that would do the trick:
list1 = ['a','a','b','a','c','b','c','a','d','a','b']
list2 = ['1','2','21','12','1','32','11','12','21','3','31']
def transform(in_list, other_list):
if len(in_list) != len(other_list):
raise ValueError("Lists must have the sema length!")
out_list = list()
out_other_list = list()
for i, c in enumerate(in_list):
for inner_list, inner_other_list in zip(out_list, out_other_list):
if c in inner_list:
inner_list.append(c)
inner_other_list.append(other_list[i])
break
else:
out_list.append([c])
out_other_list.append([other_list[i]])
return out_list, out_other_list
print transform(list1, list2)
Though I personally like soon's answer,This one successfully retrieve your desired output.
lst= sorted(zip(list1,list2),key=lambda x:x[0])
intList=[]
initial=lst[0][0]
count=0
for index,value in enumerate(lst):
if value[0]==initial:
continue
else:
intList.append(lst[count:index])
initial=value[0]
count=index
finList1=[[a for a,b in innerList] for innerList in intList]
finList2=[[b for a,b in innerList] for innerList in intList]

python splitting string twice

I'm trying to split a string twice with the goal of converting a>b where b contains numbers and is split into multiple x/y pairs
a = '{1;5}{2;7}{3;9}{4;8}'
b = [[1,5],[2,7],[3,9],[4,8]]
my code is currently this...
b = a.split('}{')
for item in b:
item.replace('{','')
item.replace('}','')
item.split(';')
the first split works correctly and returns this
b = ['{1;5','2;7','3;9','4;8}']
but manipulating the 'items in b' does not appear to work
You can use a list comprehension to do both splits at once and return a list of lists:
>>> a = '{1;5}{2;7}{3;9}{4;8}'
>>> [item.split(';') for item in a[1:-1].split('}{')]
[['1', '5'], ['2', '7'], ['3', '9'], ['4', '8']]
You have to actually modify the list b by interacting with its item. You should do something like this:
for i, s in enumerate(b):
b[i] = s.replace('{','')
b[i] = s.replace('}','')
b[i] = s.split(';')
In [9]: b
Out[9]: [['{1', '5'], ['2', '7'], ['3', '9'], ['4', '8}']]
I dont know if that's your expected output
Here are two examples where you are not affecting the list b
for item in b:
item = item.replace('{','')
item = item.replace('}','')
item = item.split(';')
In [21]: b = ['{1;5','2;7','3;9','4;8}']
In [22]: for item in b:
item = item.replace('{','')
item = item.replace('}','')
item = item.split(';')
In [23]: b
Out[23]: ['{1;5', '2;7', '3;9', '4;8}']
This one wouldnt do anything to the list b neither.
for item in b:
item.replace('{','')
item.replace('}','')
item.split(';')
This can also be done using regular expressions.
The items you are looking for inside the input string consist of
two numbers \d+
separated by a semicolon ;
enclosed in curly braces \{, \}.
The complete pattern looks like this:
pattern = r'\{(\d+);(\d+)\}'
The additional parentheses () define groups which allow extracting the numbers, for example with re.findall:
>>> for item in re.findall(pattern, a):
>>> print item
('1', '5')
('2', '7')
('3', '9')
('4', '8')
Then it is a simple matter of mapping int over the items to get the desired result:
>>> [map(int, item) for item in re.findall(pattern, a)]
[[1, 5], [2, 7], [3, 9], [4, 8]]
Some prefer list comprehensions over map:
>>> [[int(x) for x in item] for item in re.findall(pattern, a)]
[[1, 5], [2, 7], [3, 9], [4, 8]]
The function call
item.replace('{','')
does not do anything to item, since it returns a new string after the replacement. Instead, try:
item = item.replace('{','')
Similar changes need to be made for the other lines in that block.

Python: How can I take a list of lists, convert every element into strings, and return the list of lists?

For example:
list = [[11,2,3,5],[5,3,74,1,90]]
returns the same thing, only everything is a str instead of an int.
I want to be able to use .join on them. Thanks!
If you only ever go 2 lists deep:
>>> l = [[11, 2, 3, 5], [5, 3, 74, 1, 90]]
>>> [[str(j) for j in i] for i in l]
[['11', '2', '3', '5'], ['5', '3', '74', '1', '90']]
I'd use a list-comp and map for this one:
[ map(str,x) for x in lst ]
But I suppose py3.x would need an addition list in there (yuck).
[ list(map(str,x)) for x in lst ]
As a side note, you can't use join on this list we return anyway. I'm guessing you want to do something like this:
for x in lst:
print ("".join(x))
If that's the case, you can forgo the conversion all together and just do it when you're joining:
for x in lst:
print ("".join(str(item) for item in x))

Categories