Is there a way to subtract 3 from every digit of a number?
Terry Reedy
tjreedy at udel.edu
Sat Feb 20 13:51:56 EST 2021
On 2/20/2021 12:02 PM, jak wrote:
> Il 20/02/2021 15:40, C W ha scritto:
>> Hello everyone,
>>
>> I'm curious if there is a way take number and back each digit by 3 ?
>>
>> 2342 becomes 9019
>> 8475 becomes 5142
>> 5873 becomes 2540
>>
>> The tricky part is that 2 becomes 9, not -1.
>>
>> Here's my toy example and what I attempted,
>>> test_series = pd.Series(list(['2342', '8475', '5873']))
>>> test_series
>> 0 2342
>> 1 8475
>> 2 5873
>> dtype: object
>>
>>> test_series.str.split('')
>> [, 2, 3, 4, 2, ]
>> [, 8, 4, 7, 5, ]
>> [, 5, 8, 7, 3, ]
>> dtype: object
>>
>> What a good approach to this? Is there a method or function that
>> should be
>> handling this?
MRAB gave the proper answer -- str.translate (and str.maketrans.
> >>> num='0123456789'
> >>> n=8475
> >>> sn = ''
> >>> for x in str(n):
> sn += num[(int(x) - 3) % 10]
> >>> int(sn)
> 5142
This works, but suggesting to beginners that they build strings with +=
is an O(n*n) trap. Try it with a string of millions of digits. Much
better to use str.join
''.join(num[(int(c)-3) % 10] for c in '9876543210')
#'6543210987'
Even better, improve your string lookup idea to avoid the arithmetic.
lookup1 = '7890123456'
''.join(lookup1[int(c)] for c in '9876543210')
#'6543210987'
To avoid the int call, make a lookup dictionary
lookup2 = {a:b for a, b in zip('0123456789', '7890123456')}
''.join(lookup2[c] for c in '9876543210')
#'6543210987'
To run faster, use the str methods maketrans and translate to do the
same thing.
lookup3 = str.maketrans('0123456789', '7890123456')
'9876543210'.translate(lookup3)
#'6543210987'
Note that "built-in function" str.maketrans is in effect a static method
of the str class and is not an instance method.
'0123456789'.maketrans('7890123456') does not work. The reason is that
the first argument can be a dict instead of a string. Indeed, the dict
could be the char-char mapping above created with the dict comprehension.
Also, the resulting dict maps unicode ordinals to unicode ordinals,
rather than chars to chars, because at the C level, a string *is* a
sequence of unsigned ints with a PyObject wrapper.
>>> lookup3
{48: 55, 49: 56, 50: 57, 51: 48, 52: 49, 53: 50, 54: 51, 55: 52, 56: 53,
57: 54}
In Python, this is
{ord(a):ord(b) for a, b in zip('0123456789', '7890123456')}
--
Terry Jan Reedy
More information about the Python-list
mailing list