Mailing List Archive

Is there a way to subtract 3 from every digit of a number?
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?

Thanks so much!

Mike
--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
On 2021-02-20 at 09:40:48 -0500,
C W <tmrsg11@gmail.com> wrote:

> 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?

I'm assuming that this is homework or some other academic exercise, so
I'm being deliberately vague on some of the details. That said:

Break it down.

(1) Write a function that takes a number and returns the result of
subtracting three from it. This function should also handle the
"special" cases of 0, 1, and 2. Look up the modulo operator for a
better way than actually special-casing them.

(2) Python has several ways of building a list by transforming the
elements of a list one at a time and building a new list from the
results. Consider a simple iterative approach, but also look up the
builtin "map" function and "list comprehensions."

One interesting decision is where to convert the individual digits of
the original numbers from strings to integers. There are arguments for
doing it in either of the parts I've just outlined, as well as making it
a sort of Part 1a and applying both Part 1 and Part 1a to each digit.

> Thanks so much!

HTH,
Dan
--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
On 2021-02-20 14:40, C W wrote:
> 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?
>
Have a look at the 'translate' method of the 'str' class.
--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
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?
>
> Thanks so much!
>
> Mike
>

>>> num='0123456789'
>>> n=8475
>>> sn = ''
>>> for x in str(n):
sn += num[(int(x) - 3) % 10]


>>> int(sn)
5142
>>>
--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
On 2021-02-20, MRAB <python@mrabarnett.plus.com> wrote:

> Have a look at the 'translate' method of the 'str' class.

That's very clever, but being too clever on homework assignemnts
doesn't always get a good grade. If they've just studied iteration,
the modulus operator, and int/str conversions, then I'd avise using
the "dumb" method.

--
Grant



--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
Convert to a str.
Convert to a list of ints, one for each digit
Add 7 mod 10, for each digit in the list
Convert to a list of single-character str's
Catenate those str's back together
Convert to a single int



On Sat, Feb 20, 2021 at 6:45 AM C W <tmrsg11@gmail.com> wrote:

> 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?
>
> Thanks so much!
>
> Mike
> --
> https://mail.python.org/mailman/listinfo/python-list
>
--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
On 2021-02-20, Dan Stromberg <drsalists@gmail.com> wrote:

> Convert to a str.
> Convert to a list of ints, one for each digit
> Add 7 mod 10, for each digit in the list

I'd probably subtract 3 (mod 10), so as to more obviously match the
stated requirement.

> Convert to a list of single-character str's
> Catenate those str's back together
> Convert to a single int


--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
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


--
https://mail.python.org/mailman/listinfo/python-list
RE: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
Wouldn't it be nice, Grant, if Homework was assigned with statements like:

"Using only the features of the language covered up to chapter 3, meaning
individual variables and lists of them and simple loops and only using the
arithmetic built-in variable of +, -, % ... Solve this problem ...."

But there is an actual silly model and application to this homework
assignment. Consider the kind of lock shown in the video (or skip the video)
that has three or more wheels of sorts containing digits 0-9 and you rotate
each wheel to a setting read down or across like 359.

https://www.youtube.com/watch?v=BMeqkUiui20&feature=emb_logo

If you are lazy, you can put the lock on your locker and move each wheel the
same number of units in one direction. It is now securely locked and might
show 682 or 026 and if nobody touches it and perturbs the setting, you can
come back and perturb it back three units the other way (or continue seven
more) and open it.

See? A Very practical (albeit impractical) example of how this might be
fractionally useful!

I wrote a solution to the problem the student asked for that I chose not to
share here that is one line of code including an embedded list comprehension
to do the loop. If a student of mine in a beginning class offered me that
solution, I would be fairly certain it was NOT their work, though, nor what
I wanted them to do.

Now the translate method, albeit elegant, is again not likely to be the one
wanted as they probably have no idea that functionality exists. Heck, in
some languages, they may not yet know looping constructs exist and be asked
to use something like a GOTO! LOL!

And, somewhere out there is something that implements the commonly (at least
in the past) rot13 semi-cryptography of rotating the alphabet for fun and
profit. You probably can load such a module and find a function that can
rotate a numeric string by 3 or -3 and use that for a trivial solution.

None of the above should be considered as having done the darn assignment as
requested.

However, if a student gave me a decent solution and ADDED that some search
and research suggested other advanced methods they might use on the job
later, sure, maybe they get extra credit.

-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of Grant Edwards
Sent: Saturday, February 20, 2021 12:31 PM
To: python-list@python.org
Subject: Re: Is there a way to subtract 3 from every digit of a number?

On 2021-02-20, MRAB <python@mrabarnett.plus.com> wrote:

> Have a look at the 'translate' method of the 'str' class.

That's very clever, but being too clever on homework assignemnts doesn't
always get a good grade. If they've just studied iteration, the modulus
operator, and int/str conversions, then I'd avise using the "dumb" method.

--
Grant



--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
On 21/02/2021 06.02, 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?
>>
>> Thanks so much!
>>
>> Mike
>>
>
>>>> num='0123456789'
>>>> n=8475
>>>> sn = ''
>>>> for x in str(n):
>     sn += num[(int(x) - 3) % 10]
>
>     
>>>> int(sn)
> 5142
>>>>


This code doesn't *look* correct (in the original post, via email
reflector) because the loop is not indented


Per previous respondents identifying it as likely to be an 'homework
assignment', does it help the student if you/me/we "give" the answer?
How has the student proven that (s)he has learned the material?
(apologies for criticism: I readily assume your motivation was to be
helpful)


The problem is a Caesar Cipher - disguised, because most examples/usage
of such is for alphanumeric messages. This topic is often used for ComSc
examples to demonstrate modulo arithmetic and/or circular data
structures, eg a bounded-queue (per other's responses).
--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
On Sat, Feb 20, 2021 at 09:40:48AM -0500, C W wrote:
> 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.
> [...]

I just wrote a very short code can fulfill your needs:

a = 2342
b = int("".join(map(lambda x: str((int(x)-3)%10) ,list(str(a)))))

It does the following things:
1. Convert a number into a string, and then convert this string into
a list of single characters.
2. Write a lamdba expression to apply your conversion rules to a
single-character type number (just subtract 3 and then modulo 10).
3. Apply the lambda expression to the above string list through map.
4. Finally join the modified list into a string and convert it into an
integer.

--
OpenPGP fingerprint: 3C47 5977 4819 267E DD64 C7E4 6332 5675 A739 C74E
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
On Sat, Feb 20, 2021 at 7:13 PM Ming <ming@pgp.cool> wrote:

> I just wrote a very short code can fulfill your needs:
>
> a = 2342
> b = int("".join(map(lambda x: str((int(x)-3)%10) ,list(str(a)))))
>
I tend to favor plenty of temporary variables with descriptive names, but
this is indeed short.

Apart from that, you may find that using a generator expression is shorter
and clearer than map+lambda. It should allow to additionally eliminate the
list conversion.

So in the terse form you've got there, it'd be more like:
b = int(''.join(str((int(x) - 3) % 10) for x in str(a))

But in real life, I'd try to use descriptive variable names for some of the
subexpressions in that. This makes reading and debugging simpler, which is
important because the maintenance phase of software is almost always much
longer and costly than the development phase. And although you could do a
generator expression for each of the different parts of (int(x) - 3) % 10,
I kinda like having a named function for just that piece.

So maybe:
def rot_3(character):
"""Convert to int, subtract 3 and mod 10."""
digit = int(character)
assert 0 <= digit <= 9
return (digit - 3) % 10


def descriptive_minus_three_caesar(input_number):
"""Convert to a -3 caesar cypher on an integer."""
string_number = str(input_number)
rotated_digits = (rot_3(character) for character in string_number)
output_string = ''.join(str(digit) for digit in rotated_digits)
output_number = int(output_string)
return output_number
--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
On Sun, Feb 21, 2021 at 3:50 PM Dan Stromberg <drsalists@gmail.com> wrote:
>
> On Sat, Feb 20, 2021 at 7:13 PM Ming <ming@pgp.cool> wrote:
>
> > I just wrote a very short code can fulfill your needs:
> >
> > a = 2342
> > b = int("".join(map(lambda x: str((int(x)-3)%10) ,list(str(a)))))
> >
> I tend to favor plenty of temporary variables with descriptive names, but
> this is indeed short.
>
> Apart from that, you may find that using a generator expression is shorter
> and clearer than map+lambda. It should allow to additionally eliminate the
> list conversion.

For what it's worth, map doesn't require list conversion either - it's
perfectly happy (as are most things in Python) to iterate over a
string.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
On 2021-02-20 at 20:49:15 -0800,
Dan Stromberg <drsalists@gmail.com> wrote:

> On Sat, Feb 20, 2021 at 7:13 PM Ming <ming@pgp.cool> wrote:
>
> > I just wrote a very short code can fulfill your needs:
> >
> > a = 2342
> > b = int("".join(map(lambda x: str((int(x)-3)%10) ,list(str(a)))))
> >
> I tend to favor plenty of temporary variables with descriptive names, but
> this is indeed short.
>
> Apart from that, you may find that using a generator expression is shorter
> and clearer than map+lambda. It should allow to additionally eliminate the
> list conversion.
>
> So in the terse form you've got there, it'd be more like:
> b = int(''.join(str((int(x) - 3) % 10) for x in str(a))
>
> But in real life, I'd try to use descriptive variable names for some of the
> subexpressions in that. This makes reading and debugging simpler, which is
> important because the maintenance phase of software is almost always much
> longer and costly than the development phase. And although you could do a
> generator expression for each of the different parts of (int(x) - 3) % 10,
> I kinda like having a named function for just that piece.
>
> So maybe:
> def rot_3(character):
> """Convert to int, subtract 3 and mod 10."""
> digit = int(character)
> assert 0 <= digit <= 9
> return (digit - 3) % 10
>
>
> def descriptive_minus_three_caesar(input_number):
> """Convert to a -3 caesar cypher on an integer."""
> string_number = str(input_number)
> rotated_digits = (rot_3(character) for character in string_number)
> output_string = ''.join(str(digit) for digit in rotated_digits)
> output_number = int(output_string)
> return output_number

>>> descriptive_minus_three_caesar('38')
5

The problem is underspecified, and the examples are lacking, but based
on the phrase "each digit" and the examples that contain a 3, I'd prefer
to see "38" become "05."
--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
Thanks so much everyone, I appreciate it!

Ming, your solution is awesome. More importantly, very clear explanations
on how and why. So, I appreciate that.

Thanks again, cheers!

Mike

On Sun, Feb 21, 2021 at 12:08 AM <2QdxY4RzWzUUiLuE@potatochowder.com> wrote:

> On 2021-02-20 at 20:49:15 -0800,
> Dan Stromberg <drsalists@gmail.com> wrote:
>
> > On Sat, Feb 20, 2021 at 7:13 PM Ming <ming@pgp.cool> wrote:
> >
> > > I just wrote a very short code can fulfill your needs:
> > >
> > > a = 2342
> > > b = int("".join(map(lambda x: str((int(x)-3)%10) ,list(str(a)))))
> > >
> > I tend to favor plenty of temporary variables with descriptive names, but
> > this is indeed short.
> >
> > Apart from that, you may find that using a generator expression is
> shorter
> > and clearer than map+lambda. It should allow to additionally eliminate
> the
> > list conversion.
> >
> > So in the terse form you've got there, it'd be more like:
> > b = int(''.join(str((int(x) - 3) % 10) for x in str(a))
> >
> > But in real life, I'd try to use descriptive variable names for some of
> the
> > subexpressions in that. This makes reading and debugging simpler, which
> is
> > important because the maintenance phase of software is almost always much
> > longer and costly than the development phase. And although you could do
> a
> > generator expression for each of the different parts of (int(x) - 3) %
> 10,
> > I kinda like having a named function for just that piece.
> >
> > So maybe:
> > def rot_3(character):
> > """Convert to int, subtract 3 and mod 10."""
> > digit = int(character)
> > assert 0 <= digit <= 9
> > return (digit - 3) % 10
> >
> >
> > def descriptive_minus_three_caesar(input_number):
> > """Convert to a -3 caesar cypher on an integer."""
> > string_number = str(input_number)
> > rotated_digits = (rot_3(character) for character in string_number)
> > output_string = ''.join(str(digit) for digit in rotated_digits)
> > output_number = int(output_string)
> > return output_number
>
> >>> descriptive_minus_three_caesar('38')
> 5
>
> The problem is underspecified, and the examples are lacking, but based
> on the phrase "each digit" and the examples that contain a 3, I'd prefer
> to see "38" become "05."
> --
> https://mail.python.org/mailman/listinfo/python-list
>
--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
I do want to follow up, if I may. In Ming's example,

a = 2342
b = int("".join(map(lambda x: str((int(x)-3)%10) ,list(str(a)))))

What's the best approach to apply to a dataframe column, rather than just
one value? Here's my attempt using df[col_1''].apply(),
df['col_1'].apply(lambda:a int("".join(map(lambda x: str((int(x)-3)%10)
,list(str(a))))))

Thanks!

On Sun, Feb 21, 2021 at 9:12 AM C W <tmrsg11@gmail.com> wrote:

> Thanks so much everyone, I appreciate it!
>
> Ming, your solution is awesome. More importantly, very clear explanations
> on how and why. So, I appreciate that.
>
> Thanks again, cheers!
>
> Mike
>
> On Sun, Feb 21, 2021 at 12:08 AM <2QdxY4RzWzUUiLuE@potatochowder.com>
> wrote:
>
>> On 2021-02-20 at 20:49:15 -0800,
>> Dan Stromberg <drsalists@gmail.com> wrote:
>>
>> > On Sat, Feb 20, 2021 at 7:13 PM Ming <ming@pgp.cool> wrote:
>> >
>> > > I just wrote a very short code can fulfill your needs:
>> > >
>> > > a = 2342
>> > > b = int("".join(map(lambda x: str((int(x)-3)%10) ,list(str(a)))))
>> > >
>> > I tend to favor plenty of temporary variables with descriptive names,
>> but
>> > this is indeed short.
>> >
>> > Apart from that, you may find that using a generator expression is
>> shorter
>> > and clearer than map+lambda. It should allow to additionally eliminate
>> the
>> > list conversion.
>> >
>> > So in the terse form you've got there, it'd be more like:
>> > b = int(''.join(str((int(x) - 3) % 10) for x in str(a))
>> >
>> > But in real life, I'd try to use descriptive variable names for some of
>> the
>> > subexpressions in that. This makes reading and debugging simpler,
>> which is
>> > important because the maintenance phase of software is almost always
>> much
>> > longer and costly than the development phase. And although you could
>> do a
>> > generator expression for each of the different parts of (int(x) - 3) %
>> 10,
>> > I kinda like having a named function for just that piece.
>> >
>> > So maybe:
>> > def rot_3(character):
>> > """Convert to int, subtract 3 and mod 10."""
>> > digit = int(character)
>> > assert 0 <= digit <= 9
>> > return (digit - 3) % 10
>> >
>> >
>> > def descriptive_minus_three_caesar(input_number):
>> > """Convert to a -3 caesar cypher on an integer."""
>> > string_number = str(input_number)
>> > rotated_digits = (rot_3(character) for character in string_number)
>> > output_string = ''.join(str(digit) for digit in rotated_digits)
>> > output_number = int(output_string)
>> > return output_number
>>
>> >>> descriptive_minus_three_caesar('38')
>> 5
>>
>> The problem is underspecified, and the examples are lacking, but based
>> on the phrase "each digit" and the examples that contain a 3, I'd prefer
>> to see "38" become "05."
>> --
>> https://mail.python.org/mailman/listinfo/python-list
>>
>
--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
I got it to work! I defined a separate function, and put it into
df['col_1'].apply().

Not the most elegant, but it worked. I'm also curious how people on this
mailing list would do it.

Cheers!

On Sun, Feb 21, 2021 at 9:21 AM C W <tmrsg11@gmail.com> wrote:

> I do want to follow up, if I may. In Ming's example,
>
> a = 2342
> b = int("".join(map(lambda x: str((int(x)-3)%10) ,list(str(a)))))
>
> What's the best approach to apply to a dataframe column, rather than just
> one value? Here's my attempt using df[col_1''].apply(),
> df['col_1'].apply(lambda:a int("".join(map(lambda x: str((int(x)-3)%10)
> ,list(str(a))))))
>
> Thanks!
>
> On Sun, Feb 21, 2021 at 9:12 AM C W <tmrsg11@gmail.com> wrote:
>
>> Thanks so much everyone, I appreciate it!
>>
>> Ming, your solution is awesome. More importantly, very clear explanations
>> on how and why. So, I appreciate that.
>>
>> Thanks again, cheers!
>>
>> Mike
>>
>> On Sun, Feb 21, 2021 at 12:08 AM <2QdxY4RzWzUUiLuE@potatochowder.com>
>> wrote:
>>
>>> On 2021-02-20 at 20:49:15 -0800,
>>> Dan Stromberg <drsalists@gmail.com> wrote:
>>>
>>> > On Sat, Feb 20, 2021 at 7:13 PM Ming <ming@pgp.cool> wrote:
>>> >
>>> > > I just wrote a very short code can fulfill your needs:
>>> > >
>>> > > a = 2342
>>> > > b = int("".join(map(lambda x: str((int(x)-3)%10) ,list(str(a)))))
>>> > >
>>> > I tend to favor plenty of temporary variables with descriptive names,
>>> but
>>> > this is indeed short.
>>> >
>>> > Apart from that, you may find that using a generator expression is
>>> shorter
>>> > and clearer than map+lambda. It should allow to additionally
>>> eliminate the
>>> > list conversion.
>>> >
>>> > So in the terse form you've got there, it'd be more like:
>>> > b = int(''.join(str((int(x) - 3) % 10) for x in str(a))
>>> >
>>> > But in real life, I'd try to use descriptive variable names for some
>>> of the
>>> > subexpressions in that. This makes reading and debugging simpler,
>>> which is
>>> > important because the maintenance phase of software is almost always
>>> much
>>> > longer and costly than the development phase. And although you could
>>> do a
>>> > generator expression for each of the different parts of (int(x) - 3) %
>>> 10,
>>> > I kinda like having a named function for just that piece.
>>> >
>>> > So maybe:
>>> > def rot_3(character):
>>> > """Convert to int, subtract 3 and mod 10."""
>>> > digit = int(character)
>>> > assert 0 <= digit <= 9
>>> > return (digit - 3) % 10
>>> >
>>> >
>>> > def descriptive_minus_three_caesar(input_number):
>>> > """Convert to a -3 caesar cypher on an integer."""
>>> > string_number = str(input_number)
>>> > rotated_digits = (rot_3(character) for character in
>>> string_number)
>>> > output_string = ''.join(str(digit) for digit in rotated_digits)
>>> > output_number = int(output_string)
>>> > return output_number
>>>
>>> >>> descriptive_minus_three_caesar('38')
>>> 5
>>>
>>> The problem is underspecified, and the examples are lacking, but based
>>> on the phrase "each digit" and the examples that contain a 3, I'd prefer
>>> to see "38" become "05."
>>> --
>>> https://mail.python.org/mailman/listinfo/python-list
>>>
>>
--
https://mail.python.org/mailman/listinfo/python-list
RE: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
Mike,

You moved the goalpost.

Some of us here have been speculating you were asking what we call a
homework question here. The problem seemed to be the kind asked for that can
be done using fairly simple commands in python combined together.

Of course, some of the answers posted used ideas usually not taught early
and that had to be explained. The one you liked uses anonymous functions
handed to a function that repeatedly applies it to a list of items created
from taking a number apart after it is I string form and then recombines it.

My method is straightforward enough and similar to another posting because
it just follows the logic.

>>> start = 1234567890987654321
>>> int(''.join([str((int(dig)+3) % 10) for dig in str(start)]))
4567890123210987654

But you just moved the goalpost by talking about using a data.frame as that
(and I assume numpy and pandas) are not very basic Python.

So think about it. You have a column in a data.frame. How do you apply other
transformations to it? In one sense, a column in a data.frame is just one of
many kinds of ordered collects in Python, not much different than a list.
How do you apply a set of instructions to take in one collection and replace
it with another computed item by item?

Since you know about making your own functions, you know that a clean way of
doing many things is to encapsulate the gory details in a function and call
it the usual way to apply the transformation. Sure, you could use another
anonymous function and make it messier to read.

And, if you know of the capabilities of a data.frame structure, you use the
method that it already offers and hand it your function in one of multiple
ways.

Can you satisfy our curiosity about what this functionality is for, now that
it seems you may have a bigger purpose? Or, is it HW for a more advanced
class?


-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of C W
Sent: Sunday, February 21, 2021 9:21 AM
To: Python <python-list@python.org>
Subject: Re: Is there a way to subtract 3 from every digit of a number?

I do want to follow up, if I may. In Ming's example,

a = 2342
b = int("".join(map(lambda x: str((int(x)-3)%10) ,list(str(a)))))

What's the best approach to apply to a dataframe column, rather than just
one value? Here's my attempt using df[col_1''].apply(),
df['col_1'].apply(lambda:a int("".join(map(lambda x: str((int(x)-3)%10)
,list(str(a))))))

Thanks!

On Sun, Feb 21, 2021 at 9:12 AM C W <tmrsg11@gmail.com> wrote:

> Thanks so much everyone, I appreciate it!
>
> Ming, your solution is awesome. More importantly, very clear
> explanations on how and why. So, I appreciate that.
>
> Thanks again, cheers!
>
> Mike
>
> On Sun, Feb 21, 2021 at 12:08 AM <2QdxY4RzWzUUiLuE@potatochowder.com>
> wrote:
>
>> On 2021-02-20 at 20:49:15 -0800,
>> Dan Stromberg <drsalists@gmail.com> wrote:
>>
>> > On Sat, Feb 20, 2021 at 7:13 PM Ming <ming@pgp.cool> wrote:
>> >
>> > > I just wrote a very short code can fulfill your needs:
>> > >
>> > > a = 2342
>> > > b = int("".join(map(lambda x: str((int(x)-3)%10) ,list(str(a)))))
>> > >
>> > I tend to favor plenty of temporary variables with descriptive
>> > names,
>> but
>> > this is indeed short.
>> >
>> > Apart from that, you may find that using a generator expression is
>> shorter
>> > and clearer than map+lambda. It should allow to additionally
>> > eliminate
>> the
>> > list conversion.
>> >
>> > So in the terse form you've got there, it'd be more like:
>> > b = int(''.join(str((int(x) - 3) % 10) for x in str(a))
>> >
>> > But in real life, I'd try to use descriptive variable names for
>> > some of
>> the
>> > subexpressions in that. This makes reading and debugging simpler,
>> which is
>> > important because the maintenance phase of software is almost
>> > always
>> much
>> > longer and costly than the development phase. And although you
>> > could
>> do a
>> > generator expression for each of the different parts of (int(x) -
>> > 3) %
>> 10,
>> > I kinda like having a named function for just that piece.
>> >
>> > So maybe:
>> > def rot_3(character):
>> > """Convert to int, subtract 3 and mod 10."""
>> > digit = int(character)
>> > assert 0 <= digit <= 9
>> > return (digit - 3) % 10
>> >
>> >
>> > def descriptive_minus_three_caesar(input_number):
>> > """Convert to a -3 caesar cypher on an integer."""
>> > string_number = str(input_number)
>> > rotated_digits = (rot_3(character) for character in
string_number)
>> > output_string = ''.join(str(digit) for digit in rotated_digits)
>> > output_number = int(output_string)
>> > return output_number
>>
>> >>> descriptive_minus_three_caesar('38')
>> 5
>>
>> The problem is underspecified, and the examples are lacking, but
>> based on the phrase "each digit" and the examples that contain a 3,
>> I'd prefer to see "38" become "05."
>> --
>> https://mail.python.org/mailman/listinfo/python-list
>>
>
--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
On Mon, Feb 22, 2021 at 1:39 AM Avi Gross via Python-list
<python-list@python.org> wrote:
> But you just moved the goalpost by talking about using a data.frame as that
> (and I assume numpy and pandas) are not very basic Python.

Given that the original post mentioned a pd.Series, I don't know how
far the goalposts actually moved :)

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
Hey Avi,

I am a long time R user now using Python. So, this is my attempt to master
the language.

The problem for me is that I often have an idea about how things are done
in R, but not sure to what functions are available in Python.

I hope that clears up some confusion.

Cheer!

On Sun, Feb 21, 2021 at 9:44 AM Chris Angelico <rosuav@gmail.com> wrote:

> On Mon, Feb 22, 2021 at 1:39 AM Avi Gross via Python-list
> <python-list@python.org> wrote:
> > But you just moved the goalpost by talking about using a data.frame as
> that
> > (and I assume numpy and pandas) are not very basic Python.
>
> Given that the original post mentioned a pd.Series, I don't know how
> far the goalposts actually moved :)
>
> ChrisA
> --
> https://mail.python.org/mailman/listinfo/python-list
>
--
https://mail.python.org/mailman/listinfo/python-list
RE: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
Chris,

I admit I must have missed that. I was trying to understand the overall request. I do most of my data.frame work in another language ????

I will say that there are many problems that live at various levels. The original request could have been about how o covert a 1-digit integer which would have been simple enough. Instead it asked for any integer to be viewed in some way as a collection of single digits and manipulated individually. What we have now in effect with a column of a data.frame is a collection of those collections. If next he askes to convert all columns of the data.frame, we get to a collection of collections of collections ????

But realistically, some of those collections already have methods in place so no need for something like writing code nesting loops within loops within loops.

I deleted all the messages and I am asking myself if anyone else provided advice or actual code that zoomed in one how to do it to a series. You clearly saw it.

-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On Behalf Of Chris Angelico
Sent: Sunday, February 21, 2021 9:41 AM
Cc: Python <python-list@python.org>
Subject: Re: Is there a way to subtract 3 from every digit of a number?

On Mon, Feb 22, 2021 at 1:39 AM Avi Gross via Python-list <python-list@python.org> wrote:
> But you just moved the goalpost by talking about using a data.frame as
> that (and I assume numpy and pandas) are not very basic Python.

Given that the original post mentioned a pd.Series, I don't know how far the goalposts actually moved :)

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
On 2021-02-21 at 09:28:39 -0500,
C W <tmrsg11@gmail.com> wrote:

> I got it to work! I defined a separate function, and put it into
> df['col_1'].apply().
>
> Not the most elegant, but it worked. I'm also curious how people on this
> mailing list would do it.

I don't know anything about pandas, but for one string of digits
(there's no clear requirements for how to handle leading zeros in the
input or the output), I'd end up with something like this:

OFF_BY_3_MAPPING = dict(zip('0123456789', '7890123456'))
def off_by_3(digits):
return ''.join(OFF_BY_3_MAPPING[c] for c in digits)
--
https://mail.python.org/mailman/listinfo/python-list
RE: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
Ah, that is an interesting, Mike, but not an informative answer. My
question is where the specific problem came from. Yes, someone used to R
and coming to Python might work at adjusting to what is different and how to
get things done. I do that all the time as one hobby is learning lots of
languages and assessing them against each other.

So care to share your solution in R which I would assume you could do
easily?

My quick and dirty attempt, of no interest to the python community, using
the R form of integer that has a maximum, and the pipe operator that will
not be in standard R for another iteration, is this:

## R code using pipes to convert an integer
## to another integer by subtracting 3
## from each digit and wrapping around from
## 2 to 9 and so on, meaning modulo 10

## Load libraries to be used
library(dplyr)

## define function to return subtraction by N mod 10
rotdown <- function(dig, by=3) (dig -by) %% 10

start <- 123456789L

## Using pipes that send output between operators

start %>%
as.character %>%
strsplit(split="") %>%
unlist %>%
as.integer %>%
rotdown %>%
as.character %>%
paste(collapse="") %>%
as.integer

When run:

> start %>%
+ as.character %>%
+ strsplit(split="") %>%
+ unlist %>%
+ as.integer %>%
+ rotdown %>%
+ as.character %>%
+ paste(collapse="") %>%
+ as.integer
[1] 890123456

The above is not meant to be efficient and I could do better if I take more
than a few minutes but is straightforward and uses the vectorized approach
so no obvious loops are needed.






-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of C W
Sent: Sunday, February 21, 2021 9:48 AM
To: Chris Angelico <rosuav@gmail.com>
Cc: Python <python-list@python.org>
Subject: Re: Is there a way to subtract 3 from every digit of a number?

Hey Avi,

I am a long time R user now using Python. So, this is my attempt to master
the language.

The problem for me is that I often have an idea about how things are done in
R, but not sure to what functions are available in Python.

I hope that clears up some confusion.

Cheer!

On Sun, Feb 21, 2021 at 9:44 AM Chris Angelico <rosuav@gmail.com> wrote:

> On Mon, Feb 22, 2021 at 1:39 AM Avi Gross via Python-list
> <python-list@python.org> wrote:
> > But you just moved the goalpost by talking about using a data.frame
> > as
> that
> > (and I assume numpy and pandas) are not very basic Python.
>
> Given that the original post mentioned a pd.Series, I don't know how
> far the goalposts actually moved :)
>
> ChrisA
> --
> https://mail.python.org/mailman/listinfo/python-list
>
--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
With numpy and pandas, it's almost always best to start off with the
simple, obvious solution.

In your case, I would recommend defining a function, and calling
`Series.map`, passing in that function.

Sometimes, however, with large datasets, it's possible to use some
pandas/numpy tricks to significantly speed up execution.

Here's an example that runs about 5x faster than the previous example on a
1-million item array. (non-scientific testing). The downside of this
approach is you have to do some mucking about with numpy's data types to do
it, which can end up with hard-to-read solutions:

def sub3(series):
chars = series.values.astype(str)
intvals = chars.view('int8')
subbed = np.mod(intvals - ord('0') - 3, 10) + ord('0')
subbed_chars = np.where(intvals, subbed, intvals).view(chars.dtype)
return pd.Series(subbed_chars)

For example, let's create a series with 1 million items:

num_lengths = np.power(10, np.random.randint(1, 7, size=1_000_000))
test_series = pd.Series(np.random.randint(0, num_lengths,
size=1_000_000)).astype(str)

calling: sub3(test_series)
takes ~ 600ms and returns the array.

Whereas the lambda technique takes 3s for me:

test_series.map(lambda a: int("".join(map(lambda x: str((int(x)-3)%10)
,list(str(a))))))

How the numpy approach works:

1. series.values returns a numpy array of the series data
2. .astype(str) - makes numpy turn the array into a native string array (as
opposed to an array of python string onbjects). Numpy arrays are
fixed-width (dynamically chosen width to hold the largest string in the
array), so each element is zero-byte padded to be the correct width. In
this case, this is fine, as we're dealing with numbers
3. chars.view('int8') - creates a zero-copy view of the array, with each
byte as its own element. I'm assuming you're using ascii numbers here, so
this is safe. For example the digit '1' will be represented as an array
element with value 49 (ascii '1').
4. To convert, say, '49' to '1', we can subtract the ascii value for '0'
(48) from each element. Most mathematical operations in numpy are
performed element-wise, so for example 'my_array - 3' subtracts 3 from each
item
5. The actual per-character maths is done using element-wise operations,
before we add the ord('0') back to each number to convert the decimal value
back to equivalent ascii character.
6. Now we have a large 1-d array of the correctly adjusted digits, but we
need to reconstruct the original joined-up numbers.
7. np.where(intvals, a, b) is a really nice numpy builtin:
https://numpy.org/doc/stable/reference/generated/numpy.where.html. It's
used here to put back the 'zero byte' padding values from the original
numpy array
8. .view(chars.dtype) creates a fixed-size string view, of the corect
dimensions based on the original chars array.
9. Finally convert the numpy array back to a pandas series object and
return.

On Sun, Feb 21, 2021 at 3:37 PM Avi Gross via Python-list <
python-list@python.org> wrote:

> Ah, that is an interesting, Mike, but not an informative answer. My
> question is where the specific problem came from. Yes, someone used to R
> and coming to Python might work at adjusting to what is different and how
> to
> get things done. I do that all the time as one hobby is learning lots of
> languages and assessing them against each other.
>
> So care to share your solution in R which I would assume you could do
> easily?
>
> My quick and dirty attempt, of no interest to the python community, using
> the R form of integer that has a maximum, and the pipe operator that will
> not be in standard R for another iteration, is this:
>
> ## R code using pipes to convert an integer
> ## to another integer by subtracting 3
> ## from each digit and wrapping around from
> ## 2 to 9 and so on, meaning modulo 10
>
> ## Load libraries to be used
> library(dplyr)
>
> ## define function to return subtraction by N mod 10
> rotdown <- function(dig, by=3) (dig -by) %% 10
>
> start <- 123456789L
>
> ## Using pipes that send output between operators
>
> start %>%
> as.character %>%
> strsplit(split="") %>%
> unlist %>%
> as.integer %>%
> rotdown %>%
> as.character %>%
> paste(collapse="") %>%
> as.integer
>
> When run:
>
> > start %>%
> + as.character %>%
> + strsplit(split="") %>%
> + unlist %>%
> + as.integer %>%
> + rotdown %>%
> + as.character %>%
> + paste(collapse="") %>%
> + as.integer
> [1] 890123456
>
> The above is not meant to be efficient and I could do better if I take more
> than a few minutes but is straightforward and uses the vectorized approach
> so no obvious loops are needed.
>
>
>
>
>
>
> -----Original Message-----
> From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
> Behalf Of C W
> Sent: Sunday, February 21, 2021 9:48 AM
> To: Chris Angelico <rosuav@gmail.com>
> Cc: Python <python-list@python.org>
> Subject: Re: Is there a way to subtract 3 from every digit of a number?
>
> Hey Avi,
>
> I am a long time R user now using Python. So, this is my attempt to master
> the language.
>
> The problem for me is that I often have an idea about how things are done
> in
> R, but not sure to what functions are available in Python.
>
> I hope that clears up some confusion.
>
> Cheer!
>
> On Sun, Feb 21, 2021 at 9:44 AM Chris Angelico <rosuav@gmail.com> wrote:
>
> > On Mon, Feb 22, 2021 at 1:39 AM Avi Gross via Python-list
> > <python-list@python.org> wrote:
> > > But you just moved the goalpost by talking about using a data.frame
> > > as
> > that
> > > (and I assume numpy and pandas) are not very basic Python.
> >
> > Given that the original post mentioned a pd.Series, I don't know how
> > far the goalposts actually moved :)
> >
> > ChrisA
> > --
> > https://mail.python.org/mailman/listinfo/python-list
> >
> --
> https://mail.python.org/mailman/listinfo/python-list
>
> --
> https://mail.python.org/mailman/listinfo/python-list
>
--
https://mail.python.org/mailman/listinfo/python-list
Re: Is there a way to subtract 3 from every digit of a number? [ In reply to ]
On 2021-02-20 13:51:56 -0500, Terry Reedy wrote:
> On 2/20/2021 12:02 PM, jak wrote:
> > >>> sn = ''
> > >>> for x in str(n):
> > ???? sn += num[(int(x) - 3) % 10]
>
>
> 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.

The problem with trying is that it might just work.

CPython has a nice optimization for the common case (the variable at the
left side is the only reference to the str) which makes that O(n).

Other Python implementations may not have that optimization (PyPy
doesn't, I would assume that Jypthon or IronPython don't either because
their method of garbage collection would make it hard).

So for a beginner, the question is: Do you care about performance on
Python implementations you don't use? For a use-case you currently don't
have?

hp


--
_ | Peter J. Holzer | Story must make more sense than reality.
|_|_) | |
| | | hjp@hjp.at | -- Charles Stross, "Creative writing
__/ | http://www.hjp.at/ | challenge!"