Joan Venge
Joan Venge

Reputation: 331062

Is there an elegant and concise syntax to do this in Python?

Basically I have a string like this:

"1,2,3 2,3,4 3,4,5 4,5,6 5,6,7 26,117,1212"

and I want to split it by spaces and then replace every i-th element in each element. So if I replace every 2nd element with 0, then the result will be:

"1,0,3 2,0,4 3,0,5 4,0,6 5,0,7 26,0,1212"

Should I just split it and then for each string element, split them inside a for loop, and then if I am at the specified index, then use the specified value, otherwise the element itself and then append this to the final string?

I thought there might be a much better/faster and shorter way to do the same thing in Python.

Upvotes: 1

Views: 123

Answers (5)

J. Katzwinkel
J. Katzwinkel

Reputation: 1953

@Joan, your approach seems about right. You can do as you suggest all at once, using list comprehension:

>>> s = "1,2,3 2,3,4 3,4,5 4,5,6 5,6,7 26,117,1212"
>>> ' '.join([','.join([[n,'0'][int(i==1)] for i,n in enumerate(e.split(','))]) 
...    for e in s.split(' ')])
1,0,3 2,0,4 3,0,5 4,0,6 5,0,7 26,0,1212

Or, for a running i:

>>> print('\n'.join([' '.join([','.join([[n,'0'][int(i==j)] 
    for j,n in enumerate(e.split(','))]) for e in s.split(' ')]) 
    for i in range(3)]))
0,2,3 0,3,4 0,4,5 0,5,6 0,6,7 0,117,1212
1,0,3 2,0,4 3,0,5 4,0,6 5,0,7 26,0,1212
1,2,0 2,3,0 3,4,0 4,5,0 5,6,0 26,117,0

In any case, s is split at spaces ('') first, each resulting fragment is itself split at commas (,), so that we can loop over the fragment's single elements, alongside a running integer [as returned by enumerate(seq)], with which we test each element for being the ith item of its fragment, in which case we overwrite it with a 0. The nested lists we got by doing all this are then reassembled bottom-up into the original input string format by reinserting the respective separator characters, using the join([...]) function.

Upvotes: 1

HYRY
HYRY

Reputation: 97291

Here is a regular expression version:

import re
a = "1,2,3 2,3,4 3,4,5 4,5,6 5,6,7 26,117,1212"

for i in range(3):
    print re.sub(r"((^| )(\d+,){%d})(\d+)" % i, r"\g<1>0", a)

the output:

0,2,3 0,3,4 0,4,5 0,5,6 0,6,7 0,117,1212
1,0,3 2,0,4 3,0,5 4,0,6 5,0,7 26,0,1212
1,2,0 2,3,0 3,4,0 4,5,0 5,6,0 26,117,0

Upvotes: 2

falsetru
falsetru

Reputation: 369094

Using numpy.matrix:

>>> import numpy as np
>>>
>>> s = "1,2,3 2,3,4 3,4,5 4,5,6 5,6,7 26,117,1212"
>>> m = np.matrix(s.replace(' ', ';').replace(',', ' '), dtype=str)
>>> m[:, 1] = '0'
>>> ' '.join(map(','.join, np.asarray(m)))
'1,0,3 2,0,4 3,0,5 4,0,6 5,0,7 26,0,1212'

Upvotes: 2

U2EF1
U2EF1

Reputation: 13259

I'm not sure what your ultimate goals are, but numpy excels at manipulating rectangles of numbers for fun and profit.

> import numpy as np; from StringIO import StringIO
> s = "1,2,3 2,3,4 3,4,5 4,5,6 5,6,7 26,117,1212"
> a = np.loadtxt(StringIO(s.replace(' ', '\n')), delimiter=',', dtype=int)
> a # ah, much better
array([[   1,    2,    3],
       [   2,    3,    4],
       [   3,    4,    5],
       [   4,    5,    6],
       [   5,    6,    7],
       [  26,  117, 1212]])
> a[:, 1] = 0 # all the rows, column 1
> a
array([[   1,    0,    3],
       [   2,    0,    4],
       [   3,    0,    5],
       [   4,    0,    6],
       [   5,    0,    7],
       [  26,    0, 1212]])
> (' '.join(['%s,%s,%s'] * len(a))) % tuple(a.flatten()) # okay, apply silly formatting
'1,0,3 2,0,4 3,0,5 4,0,6 5,0,7 26,0,1212'

Upvotes: 1

user2357112
user2357112

Reputation: 280837

nums = [[int(num) for num in substring.split(',')] for substring in s.split()]
for row in nums:
    row[1] = 0

The first line converts the input out of text format and into a list of lists of numbers, and the second and third lines replace the second item in each sublist. At this point, if you need to print the numbers or write them to a file or something, you can convert back to a string, but if you need to keep doing things with the numbers, it's probably best to keep using the nums list.

If you're going to immediately turn the data back into a string, it's not worth calling int. In that case, the code reduces to

nums = [substring.split(',') for substring in s.split()]
for row in nums:
    row[1] = '0'

and then to convert back to a string,

string_representation = ' '.join(','.join(row) for row in nums)

To replace the first or third element of every section, just replace the 1 in row[1] = '0' with the index you want to replace. 0 for the first element, 2 for the third. You can make a function taking the index you want to use:

def zero_out_column(s, index):
    nums = [substring.split(',') for substring in s.split()]
    for row in nums:
        row[index] = '0'
    return ' '.join(','.join(row) for row in nums)

Upvotes: 2

Related Questions