Question

I am trying to find an easy way to add a dot . to each 3 digit as a string ('43434' -> '43.434) and I found an interesting use of join for this task:

num = '1234567'
new_num = '.'.join(num[i:i+3] for i in range(0, len(num), 3))
# new_num = 123.456.7'

Well its close to what I want. This is what I want:

(its need to be `'1.234.567'`)

Why does it work like that? When I use slicing on join, it adds the addition for each item:

num = '2333'
>>> '.'.join(num[0:2])
<<< '2.3'
>>> '.'.join(num[0:3])
<<< '2.3.3'

I read somewhere that its called string as iterable concept. Can someone help me understand it?

Était-ce utile?

La solution 2

Your first code sample picks up 3 digits at a time of the number and joins them. Breaking it up

>>>num = '1234567'
>>>x=[num[i:i+3] for i in range(0, len(num), 3)]
>>>x
['123', '456', '7']
>>>'.'.join(x)
'123.456.7'

The num[i:i+3] part is called slicing and explained here.

While in the second part you use the join function to connect the parts again.

>>>num = '2333'
>>>num[0:2]
23 
>>>'.'.join('23')
2.3

What you want is 1.234.567, i.e. you want to start counting three digits from the end of the string. One way would be to reverse the string, do what you are doing and reverse the result.

>>> num = '1234567'
>>> num[::-1]
'7654321'
>>> '.'.join(num[::-1][i:i+3] for i in range(0, len(num), 3))[::-1]
'1.234.567'

Autres conseils

Possible way,

>>> num = '1234567'
>>> '.'.join([num[i-3 if i-3 > 0 else 0:i] for i in range(len(num),-1,-3)][::-1])
'1.234.567'

A benchmark,

$ python -mtimeit -s'num="1234567"' '".".join(num[::-1][i:i+3] for i in range(0, len(num), 3))[::-1]'
100000 loops, best of 3: 4.15 usec per loop

$ python -mtimeit -s'num="1234567"' '".".join([num[i-3 if i-3 > 0 else 0:i] for i in range(len(num), -1, -3)][::-1])'
1000000 loops, best of 3: 1.87 usec per loop

Neither one stands out as clearer to me but if you prefer the first (popular solution posted) it's only slightly slower.

If you try:

>>> a = (num[i:i+3] for i in range(0, len(num), 3))
>>> a
<generator object <genexpr> at 0x028C2B48>

So the first one is essentially using:

new_num = '.'.join(a) # iterating with generator

Alternatively, you can do with list:

new_num = '.'.join([num[i:i+3] for i in range(0, len(num), 3)]) 
# iterating with list ['123', '456', '7']

This explains your code as well, since you can see string as list:

'.'.join(num[0:3]) # num[0:3] -> '233' string -> ['2', '3', '3']

Roughly, what an iterable is is something for which this code will work:

for x in some_iterable_here:
    print(x)

The idea is that an iterable is a sequence of values. Lists are iterables. If some_iterable_here was the list [1, 23, -7, 'hello'], the code above would print out the number 1, 23, -7, and lastly the string 'hello'.

A string is one kind of iterable -- it's a sequence of characters. So if you put in the string 'hello' for some_iterable_here, it'd print out each letter individually: 'h', 'e', 'l', 'l', then finally 'o'.

What join does is take each element in an iterable containing strings (for example, a list of strings like ['one', 'two', 'three'], or just the string 'four', which is an iterable containing the strings 'f', 'o', 'u', and 'r') and return a new string that's all the strings put together, with something in between.

So when you get the slice num[0:3], that's the string '233'. Python combines each character with a period in between when you do '.'.join on it, and that's how you get '2.3.3'.

Try This Solution

(".".join([num[::-1][i:i+3] for i in range(0, len(num), 3)]))[::-1]

If I understand you:

In [15]: num = '1234567'
#Reverse string with [::-1]
In [16]: new_num = '.'.join(num[::-1][i:i+3] for i in range(0, len(num), 3))
#Repeat reverse for correct result
In [17]: new_num = new_num[::-1]
In [18]: print new_num
1.234.567
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top