Skip to content

Commit d069b5d

Browse files
petremBethanyGBNAndras
authored
robot-name approach: fix typos, minor rephrasing/improvements (#4051)
* robot-name approach: fix typos, minor rephasing/improvements - Fixed a few typos. - Rephrased here and there where I subjectively thought it useful. Please let me know if they're undesirable. - Expanded some contractions - this might help non-native speakers. - When another approach is mentioned, added link to it - hopefully this is useful rather than an distraction - I thought the explanation about the alternative to using the walrus operator was not clear, so rephrased and added a code snippet. I hope this is useful. * Update exercises/practice/robot-name/.approaches/mass-name-generation/content.md Co-authored-by: BethanyG <BethanyG@users.noreply.github.com> * Update exercises/practice/robot-name/.approaches/mass-name-generation/content.md Co-authored-by: BethanyG <BethanyG@users.noreply.github.com> * Update exercises/practice/robot-name/.approaches/mass-name-generation/content.md Co-authored-by: BethanyG <BethanyG@users.noreply.github.com> * Update exercises/practice/robot-name/.approaches/mass-name-generation/content.md Co-authored-by: BethanyG <BethanyG@users.noreply.github.com> * Update exercises/practice/robot-name/.approaches/name-on-the-fly/content.md Co-authored-by: BethanyG <BethanyG@users.noreply.github.com> * Update exercises/practice/robot-name/.approaches/name-on-the-fly/content.md Co-authored-by: BethanyG <BethanyG@users.noreply.github.com> * Update exercises/practice/robot-name/.approaches/mass-name-generation/content.md Co-authored-by: András B Nagy <20251272+BNAndras@users.noreply.github.com> * blank lines after headers and remove trailing whitespace * add blank lines around code snippets and expand one more contraction --------- Co-authored-by: BethanyG <BethanyG@users.noreply.github.com> Co-authored-by: András B Nagy <20251272+BNAndras@users.noreply.github.com>
1 parent dcbfdef commit d069b5d

File tree

3 files changed

+48
-24
lines changed

3 files changed

+48
-24
lines changed

exercises/practice/robot-name/.approaches/introduction.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
# Introduction
2-
Robot Name in Python is an interesting exercise for practising randomness.
2+
3+
Robot Name in Python is an interesting exercise for practicing randomness.
34

45
## General Guidance
5-
Two ways immedietely come to mind: generate all the possible names and then return them sequentially, or generate a random name and ensure that it's not been previously used.
6+
7+
Two ways immediately come to mind: generate all the possible names and then return them sequentially, or generate a random name and ensure that it has not been previously used.
68

79
Randomness can be a little, well, random, so **it's very easy to have an incorrect solution and still pass the tests**. It's strongly recommended to submit your solution for Code Review.
810

911
## Approach: mass name generation
12+
1013
We'd first have to generate all the possible names, shuffle them, and then use `next` (the simplest way) or maintain a `current_index` and get the name.
1114
Here's a possible way to do it:
1215

@@ -26,14 +29,17 @@ class Robot(object):
2629
def reset(self):
2730
self.name = next(NAMES)
2831
```
32+
2933
Note that selecting randomly from the list of all names would be incorrect, as there's a possibility of the name being repeated.
3034
For more detail and explanation of the code, [read here][approach-mass-name-generation].
3135

3236
## Approach: name on the fly
33-
Another approach is to generate the name on the fly and add it to a cache or a store, and checking if the generated name hasn't been used previously.
37+
38+
Another approach is to generate the name on the fly and add it to a cache or a store, checking if the generated name hasn't been used previously.
3439

3540

3641
A possible way to implement this:
42+
3743
```python
3844
from string import ascii_uppercase, digits
3945
from random import choices

exercises/practice/robot-name/.approaches/mass-name-generation/content.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# Mass Name Generation
2-
We'd first have to generate all the possible names, shuffle them, and then use `next` (the simplest way) or maintain a `current_index` and get the name.
3-
Note that selecting randomly from the list of all names would be incorrect, as there's a possibility of the name being repeated.
42

5-
Here's a possible way to do it:
3+
We first generate all the possible names, shuffle them, and then either use `next` (the simplest way) or maintain a `current_index` to get the name.
4+
Note that selecting randomly from the list of all names would be incorrect, as there is a possibility of the name being repeated.
5+
6+
One possible way to do it:
67

78
```python
89
from itertools import product
@@ -25,25 +26,27 @@ class Robot(object):
2526

2627
The first few lines of the mass name generation uses [`itertools.product`][itertools-product].
2728
The resultant code is a simplification of:
29+
2830
```python
2931
letter_pairs = (''.join((l1, l2)) for l1 in ascii_uppercase for l2 in ascii_uppercase)
3032
numbers = (str(i).zfill(3) for i in range(1000))
3133
names = [l + n for l in letter_pairs for n in numbers]
3234
```
3335

34-
After the name generation, the names are shuffled - using the [default `seed`][random-seed] in the `random` module (the current timestamp).
36+
After the name generation, the names are shuffled - using the [default `seed`][random-seed] in the `random` module (the current timestamp).
3537
When the tests reseed `random`, this has no effect as the names were shuffled before that.
3638

37-
We then set `NAMES` to the iterable of names, and in `reset`, set the robot's name to the `next(name)`.
38-
If you'd like, read more on [`iter` and `next`][iter-and-next].
39+
We then set `NAMES` to the iterable of names, and in `reset`, set the robot's name to the `next(name)`.
40+
If you are interested, you can read more on [`iter` and `next`][iter-and-next].
3941

40-
Unlike the on the fly approach, this has a relatively short "generation" time, because we're merely giving the `next` name instead of generating it.
41-
However, this has a huge startup memory and time cost, as 676,000 strings have to be calculated and stored.
42+
Unlike the [on the fly approach][approach-name-on-the-fly], this has a relatively short "generation" time, because we are merely giving the `next` name instead of generating it.
43+
However, this has a huge startup memory and time cost, as 676,000 strings have to be calculated and stored.
4244
For an approximate calculation, 676,000 strings * 5 characters / string * 1 byte / character gives 3380000 bytes or 3.38 MB of RAM - and that's just the memory aspect of it.
43-
Sounds small, but it's relatively very expensive at the beginning.
45+
Sounds small, but this might be a relatively significant startup cost.
4446

4547
Thus, this approach is inefficient in cases where only a small number of names are needed _and_ the time to set/reset the robot isn't crucial.
4648

4749
[random-seed]: https://docs.python.org/3/library/random.html#random.seed
4850
[iter-and-next]: https://www.programiz.com/python-programming/methods/built-in/iter
4951
[itertools-product]: https://www.hackerrank.com/challenges/itertools-product/problem
52+
[approach-name-on-the-fly]: https://exercism.org/tracks/python/exercises/robot-name/approaches/name-on-the-fly
Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# Find name on the fly
2-
We generate the name on the fly and add it to a cache or a store, and checking if the generated name hasn't been used previously.
2+
3+
We generate the name on the fly and add it to a cache or a store, checking to make sure that the generated name has not been used previously.
34

45
A possible way to implement this:
6+
57
```python
68
from string import ascii_uppercase, digits
79
from random import choices
@@ -10,7 +12,7 @@ cache = set()
1012

1113

1214
class Robot:
13-
def __get_name(self):
15+
def __get_name(self):
1416
return ''.join(choices(ascii_uppercase, k=2) + choices(digits, k=3))
1517

1618
def reset(self):
@@ -19,18 +21,30 @@ class Robot:
1921
cache.add(name)
2022
self.name = name
2123

22-
def __init__(self):
24+
def __init__(self):
2325
self.reset()
2426
```
25-
We use a `set` for the cache as it has a low access time, and we don't need the preservation of order or the ability to be indexed.
2627

27-
This way is merely one of the many to generate the name.
28+
We use a `set` for the cache as it has a low access time, and because we do not need the preservation of order or the ability to access by index.
29+
30+
Using `choices` is one of the many ways to generate the name.
2831
Another way might be to use `randrange` along with `zfill` for the number part, and a double `random.choice` / `random.choice` on `itertools.product` to generate the letter part.
29-
This is the shortest way, and best utilizes the Python standard library.
32+
The first is shorter, and best utilizes the Python standard library.
33+
34+
As we are using a `while` loop to check for the name generation, it is convenient to store the local `name` using the [walrus operator][walrus-operator].
35+
It's also possible to find the name once before the loop, and then find it again inside the loop, but that would be an unnecessary repetition:
36+
37+
```python
38+
def reset(self):
39+
name = self.__get_name()
40+
while name in cache:
41+
name = self.__get_name()
42+
cache.add(name)
43+
self.name = name
44+
```
3045

31-
As we're using a `while` loop to check for the name generation, it's convenient to store the local `name` using the [walrus operator][walrus-operator].
32-
It's also possible to find the name before the loop and find it again inside the loop, but that would unnecessary repetition.
3346
A helper method ([private][private-helper-methods] in this case) makes your code cleaner, but it's equally valid to have the code in the loop itself:
47+
3448
```python
3549
def reset(self):
3650
while (name := ''.join(choices(ascii_uppercase, k=2) + choices(digits, k=3))) in cache:
@@ -39,14 +53,15 @@ def reset(self):
3953
self.name = name
4054
```
4155

42-
We call `reset` from `__init__` - it's syntactically valid to do it the other way round, but it's not considered good practice to call [dunder methods][dunder-methods] directly.
56+
We call `reset` from `__init__` - it is syntactically valid to do it the other way around, but it is not considered good practice to call [dunder methods][dunder-methods] directly.
4357

4458
This has almost no startup time and memory, apart from declaring an empty `set`.
45-
Note that the _generation_ time is the same as the mass generation approach, as a similar method is used.
59+
Note that the _generation_ time is the same as the [mass generation approach][approach-mass-name-generation], as a similar method is used.
4660
However, as the name is generated at the time of setting/resetting, the method time itself is higher.
4761

48-
In the long run, if many names are generated, this is inefficient, since collisions will start being generated more often than unique names.
62+
In the long run, if many names are generated, this is inefficient, since collisions will start being generated more often than unique names.
4963

5064
[walrus-operator]: https://realpython.com/python-walrus-operator/
5165
[private-helper-methods]: https://www.geeksforgeeks.org/private-methods-in-python/
52-
[dunder-methods]: https://dbader.org/blog/python-dunder-methods
66+
[dunder-methods]: https://dbader.org/blog/python-dunder-methods
67+
[approach-mass-name-generation]: https://exercism.org/tracks/python/exercises/robot-name/approaches/mass-name-generation

0 commit comments

Comments
 (0)