Is there a "straightforward" way to convert a str containing numbers into a list of [x,y] ints?
# from: '5,4,2,4,1,0,3,0,5,1,3,3,14,32,3,5'
# to: [[5, 4], [2, 4], [1, 0], [3, 0], [5, 1], [3, 3], [14, 32], [3, 5]]
By the way, the following works, but wouldn't call it straightforward... Also, it can be assumed that the input str has been validated to make sure that it only contains an even number of numbers interleaved by commas.
num_str = '5,4,2,4,1,0,3,0,5,1,3,3,14,32,3,5'
numpairs_lst = [] # ends up as [[5, 4], [2, 4], [1, 0], ...]
current_num_str = '' # the current num within the str; stop when a comma is found
xy_pair = [] # this is one of the [x,y] pairs -> [5, 4]
for ix,c in enumerate(num_str):
if c == ',':
xy_pair.append(int(current_num_str))
current_num_str = ''
if len(xy_pair) == 2:
numpairs_lst.append(xy_pair)
xy_pair = []
else:
current_num_str += c
# and, take care of last number...
xy_pair.append(int(current_num_str))
numpairs_lst.append(xy_pair)
Number Type ConversionType int(x) to convert x to a plain integer. Type long(x) to convert x to a long integer. Type float(x) to convert x to a floating-point number. Type complex(x) to convert x to a complex number with real part x and imaginary part zero.
In Python an integer can be converted into a string using the built-in str() function. The str() function takes in any python data type and converts it into a string.
In Python an strings can be converted into a integer using the built-in int() function. The int() function takes in any python data type and converts it into a integer.
We can convert numbers to strings through using the str() method. We'll pass either a number or a variable into the parentheses of the method and then that numeric value will be converted into a string value.
There are two important one line idioms in Python that help make this "straightforward".
The first idiom, use zip(). From the Python documents:
The left-to-right evaluation order of the iterables is guaranteed. This makes possible an idiom for clustering a data series into n-length groups using zip(*[iter(s)]*n).
So applying to your example:
>>> num_str = '5,4,2,4,1,0,3,0,5,1,3,3,14,32,3,5'
>>> zip(*[iter(num_str.split(","))]*2)
[('5', '4'), ('2', '4'), ('1', '0'), ('3', '0'), ('5', '1'),
('3', '3'), ('14', '32'), ('3', '5')]
That produces tuples each of length 2.
If you want the length of the sub elements to be different:
>>> zip(*[iter(num_str.split(","))]*4)
[('5', '4', '2', '4'), ('1', '0', '3', '0'), ('5', '1', '3', '3'),
('14', '32', '3', '5')]
The second idiom is list comprehensions. If you want sub elements to be lists, wrap in a comprehension:
>>> [list(t) for t in zip(*[iter(num_str.split(","))]*4)]
[['5', '4', '2', '4'], ['1', '0', '3', '0'], ['5', '1', '3', '3'],
['14', '32', '3', '5']]
>>> [list(t) for t in zip(*[iter(num_str.split(","))]*2)]
[['5', '4'], ['2', '4'], ['1', '0'], ['3', '0'], ['5', '1'], ['3', '3'],
['14', '32'], ['3', '5']]
Any sub element groups that are not complete will be truncated by zip(). So if your string is not a multiple of 2, for example, you will loose the last element.
If you want to return sub elements that are not complete (ie, if your num_str
is not a multiple of the sub element's length) use a slice idiom:
>>> l=num_str.split(',')
>>> [l[i:i+2] for i in range(0,len(l),2)]
[['5', '4'], ['2', '4'], ['1', '0'], ['3', '0'], ['5', '1'],
['3', '3'], ['14', '32'], ['3', '5']]
>>> [l[i:i+7] for i in range(0,len(l),7)]
[['5', '4', '2', '4', '1', '0', '3'], ['0', '5', '1', '3', '3', '14', '32'],
['3', '5']]
If you want each element to be an int, you can apply that prior to the other transforms discussed here:
>>> nums=[int(x) for x in num_str.split(",")]
>>> zip(*[iter(nums)]*2)
# etc etc etc
As pointed out in the comments, with Python 2.4+, you can also replace the list comprehension with a Generator Expression by replacing the [ ]
with ( )
as in:
>>> nums=(int(x) for x in num_str.split(","))
>>> zip(nums,nums)
[(5, 4), (2, 4), (1, 0), (3, 0), (5, 1), (3, 3), (14, 32), (3, 5)]
# or map(list,zip(nums,nums)) for the list of lists version...
If your string is long, and you know that you only need 2 elements, this is more efficient.
One option:
>>> num_str = '5,4,2,4,1,0,3,0,5,1,3,3,4,3,3,5'
>>> l = num_str.split(',')
>>> zip(l[::2], l[1::2])
[('5', '4'), ('2', '4'), ('1', '0'), ('3', '0'), ('5', '1'), ('3', '3'), ('4', '3'), ('3', '5')]
Reference: str.split()
, zip()
, General information about sequence types and slicing
If you actually want integers, you could convert the list to integers first using map
:
>>> l = map(int, num_str.split(','))
Explanation:
split
creates a list of the single elements. The trick is the slicing: the syntax is list[start:end:step]
. l[::2]
will return every second element starting from the first one (so the first, third,...), whereas the second slice l[1::2]
returns every second element from the second one (so the second, forth, ...).
Update: If you really want lists, you could use map
again on the result list:
>>> xy_list = map(list, xy_list)
Note that @Johnsyweb's answer is probably faster as it seems to not do any unnecessary iterations. But the actual difference depends of course on the size of the list.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With