Reputation: 579
I have a list of items stored in a list as a list of the list. I want to remove a particular character from each item if it is found. I am able to do it if I just use the first element of the list. However, I get "IndexError: list index out of range" while using for loop.
This is my list.
list1 = [['2.6x3.65'],[],['2','2.9x1.7','2.5x1.3']]
This is how I do for the first element.
if('x' in list1[0][0]):
rep1 = re.sub('x', ', ', list1[0][0])
This gives me the output as 2.6, 3.65 in string format which I can later convert to float.
However, when I implement the same using for loop using the following code:
for i in list1[i][i]:
if('x' in list1[i][i]):
rep2 = re.sub('x', ', ', list1[i][i])
It gives "IndexError: list index out of range" while using for loop.
My expected result is to get like the following:
list2 = [[2.6, 3.65],[],[2, 2.9, 1.7, 2.5, 1.3]]
Upvotes: 1
Views: 1140
Reputation: 26886
Your code is likely getting the error because of this line:
for i in list1[i][i]:
...
It is not clear what the value of i
is when evaluating list[i][i]
, but it would not work regardless, because what you would like to do is looping through your main list and also within each of its elements, which are also lists.
While you could figure this out with explicit indexing, Python offers you a better approach, namely looping through the elements directly.
Most importantly, in general, your regular expression approach would not be working because:
re.sub('x', ', ', list1[0][0])
is actually producing a string, which when printed, looks identical to the way Python would print a list of numbers, but it is not a list of numbers!
What you want to do instead is to convert your string to a numeric type.
If all you need is a list of float
s, then just casting a valid text representation of a float
would do the trick e.g. float('1.5') == 1.5
. The same would hold for int
, e.g. int('432') == 432
(but int('1.5')
will raise a ValueError
).
If you want to have different objects for int
s and float
s, as your expected output indicates, you could just first try to convert to int
and if that fails, convert to float
:
def to_number(value):
try:
value = int(value)
except ValueError:
value = float(value)
finally:
return value
With this in mind, you now need to make sure that the input of that function is going to be a string with a number.
Obviously, 1x2
or even 1, 2
are not, i.e. both int('1x2')
and int('1, 2')
(or with float
instead of int
) would rise a ValueError
.
However, Python offers a simple way of parsing (well, splitting) that string in such a way that you would get '1'
and '2'
in a list:
'1x2'.split('x') == ['1', '2']
This also has the rather benign behavior of gracefully producing a consistent output even if you apply this to a text not containing the char
to split, e.g.:
'1'.split('x') == ['1']
With all this building blocks, it is now possible to craft a sensible solution (making heavy use of list comprehensions):
list2 = [
[to_number(x) for elem in inner_list for x in elem.split('x')]
for inner_list in list1]
print(list2)
# [[2.6, 3.65], [], [2, 2.9, 1.7, 2.5, 1.3]]
(EDIT: added a number of explanations and wrote the code fully as list comprehensions).
Upvotes: 2
Reputation: 7812
You can use nested list comprehension:
list1 = [['2.6x3.65'], [], ['2', '2.9x1.7', '2.5x1.3']]
list2 = [sum([list(map(float, i.split('x'))) for i in l], []) for l in list1]
Output:
[[2.6, 3.65], [], [2.0, 2.9, 1.7, 2.5, 1.3]]
To not mix map()
with list comprehension:
list2 = [[float(e) for i in l for e in i.split('x')] for l in list1]
Upvotes: 3
Reputation: 5051
One approach would be to loop over your list and append to a new one:
list1 = [['2.6x3.65'],[],['2','2.9x1.7','2.5x1.3']]
new_l = []
for l in list1:
temp = []
for elem in l:
new_s = elem.split("x")
temp.extend([float(x) for x in new_s])
new_l.append(temp)
print(new_l)
# [[2.6, 3.65], [], [2.0, 2.9, 1.7, 2.5, 1.3]]
Upvotes: 1
Reputation: 82755
This is one approach using ast
and itertools.chain
.
Ex:
from itertools import chain
import ast
list1 = [['2.6x3.65'],[],['2','2.9x1.7','2.5x1.3']]
result = []
for i in list1:
temp = []
for j in i:
temp.append(map(ast.literal_eval, j.split("x")))
result.append(list(chain.from_iterable(temp)))
print(result)
Output:
[[2.6, 3.65], [], [2, 2.9, 1.7, 2.5, 1.3]]
Upvotes: 1