7

What is the most Pythonic way to right split into groups of threes? I've seen this answer https://stackoverflow.com/a/2801117/1461607 but I need it to be right aligned. Preferably a simple efficient one-liner without imports.

  • '123456789' = ['123','456','789']
  • '12345678' = ['12','345','678']
  • '1234567' = ['1','234','567']

7 Answers 7

13

Another way, not sure about efficiency (it'd be better if they were already numbers instead of strings), but is another way of doing it in 2.7+.

for i in map(int, ['123456789', '12345678', '1234567']):
    print i, '->', format(i, ',').split(',')

#123456789 -> ['123', '456', '789']
#12345678 -> ['12', '345', '678']
#1234567 -> ['1', '234', '567']
Sign up to request clarification or add additional context in comments.

5 Comments

eh? I can't see where the 'groups of three' bit comes into this.
@user1461607 not sure what you mean but format(num, ',') formats a string into conventional , delimited blocks of 3, so that splitting on , gives you the required result.
@user1461607 it's a useful feature for formatting numbers (as it's quite common)... so you could one liner it to be format(int('1234567'), ',').split(',') if you wanted...
clever solution :-) I wonder how it compares to mine performance wise
@FabianHenze The thing is that the format/split approach is utilising the underlying implementation to do the "dirty work" - so will be faster... The bottleneck comes with the converting the string to an integer first for the formatting to work...
7

simple (iterated from the answer in your link):

[int(a[::-1][i:i+3][::-1]) for i in range(0, len(a), 3)][::-1]

Explanation : a[::-1] is the reverse list of a We will compose the inversion with the slicing.

Step one : reverse the list

 a           =   a[::-1]
'123456789' - > '987654321'

Step Two : Slice in parts of three's

 a[i]           =   a[i:i+3]
 '987654321'    ->  '987','654','321'

Step Three : invert the list again to present the digits in increasing order

 a[i]           =  int(a[i][::-1])
 '987','654','321' -> 789, 654, 123

Final Step : invert the whole list

 a           =   a[::-1]
 789, 456, 123 -> 123, 456, 789

Bonus : Functional synthetic sugar

It's easier to debug when you have proper names for functions

invert = lambda a: a[::-1]
slice  = lambda array, step : [ int( invert( array[i:i+step]) ) for i in range(len(array),step)  ]

answer = lambda x: invert ( slice ( invert (x) , 3 ) )
answer('123456789')
#>> [123,456,789]

1 Comment

Doesn't work. I get ValueError: invalid literal for int() with base 10: '' for a = '123456789'.
5

This is the best I came up with:

[a[max(i-3,0):i] for i in range(len(a), 0, -3)][::-1]

and another one, which works without inverting the list, but is slightly more ugly:

[a[max(0,i):i+3] for i in range((len(a)-1)%3-2, len(a), 3)]

Comments

1

The shortest isn't always the most Pythonic.

def by3(s):
    out = []
    while len(s):
        out.insert(0, s[-3:])
        s = s[:-3]
    return out
>>> by3(a)
['12', '345', '678'] 

Comments

1

A four liner:

splitted_number = []
while number:
    number, r = number[:-3], number[-3:]
    splitted_number.insert(0, r)

Comments

1

My 2cents if someone find this usefull: textwrap is built-in module that do the thing.

from textwrap import wrap

a = '123456789'
b = wrap(a, 3)
>>> b ['123', '456', '789']

Comments

0

Expanding @Manu answer,

from textwrap import wrap

a = '123456789'
b = wrap(a, 3)
print(b)

newlist = []

for i in b:
    newlist.append(int(i))
   
print(newlist)
['123', '456', '789']
[123, 456, 789]

[Program finished] 

or

n = 1234567890
v = [] 
while n > 0:
    n, r = divmod(n, 1000) 
    v.insert(0, r)

print(v)
[1, 234, 567, 890]

[Program finished]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.