Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions maths/look_and_say_sequence.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"""
Look-and-Say Sequence
=====================
The Look-and-Say sequence is a sequence of integers where each term is
generated by reading the digits of the previous term aloud.

Starting from "1":
1 -> "one 1" -> 11
11 -> "two 1s" -> 21
21 -> "one 2, one 1" -> 1211
1211 -> "one 1, one 2, two 1s" -> 111221
...

Reference: https://en.wikipedia.org/wiki/Look-and-say_sequence

Examples:
>>> list(look_and_say_sequence(1))
['1']
>>> list(look_and_say_sequence(5))
['1', '11', '21', '1211', '111221']
>>> next_term('1')
'11'
>>> next_term('111221')
'312211'
>>> next_term('')
Traceback (most recent call last):
...
ValueError: Input term must be a non-empty string of digits.
"""

from itertools import groupby


def next_term(term: str) -> str:
"""
Generate the next term in the Look-and-Say sequence.

Each group of consecutive identical digits is replaced by
the count of digits followed by the digit itself.

Args:
term: A non-empty string of digits representing the current term.

Returns:
The next term in the sequence as a string.

Raises:
ValueError: If the input term is empty.

Examples:
>>> next_term('1')
'11'
>>> next_term('11')
'21'
>>> next_term('21')
'1211'
>>> next_term('1211')
'111221'
>>> next_term('111221')
'312211'
"""
if not term:
raise ValueError("Input term must be a non-empty string of digits.")
return "".join(str(len(list(group))) + digit for digit, group in groupby(term))


def look_and_say_sequence(num_terms: int, start: str = "1"):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: look_and_say_sequence. If the function does not return a value, please provide the type hint as: def function() -> None:

"""
Generate the Look-and-Say sequence up to num_terms terms.

Args:
num_terms: The number of terms to generate (must be >= 1).
start: The starting term (default is "1").

Yields:
Each term of the sequence as a string.

Raises:
ValueError: If num_terms is less than 1.

Examples:
>>> list(look_and_say_sequence(1))
['1']
>>> list(look_and_say_sequence(5))
['1', '11', '21', '1211', '111221']
>>> list(look_and_say_sequence(6))
['1', '11', '21', '1211', '111221', '312211']
>>> list(look_and_say_sequence(0))
Traceback (most recent call last):
...
ValueError: num_terms must be a positive integer.
"""
if num_terms < 1:
raise ValueError("num_terms must be a positive integer.")
term = start
for _ in range(num_terms):
yield term
term = next_term(term)


if __name__ == "__main__":
import doctest

doctest.testmod()

print("Look-and-Say Sequence (first 8 terms):")
for i, term in enumerate(look_and_say_sequence(8), start=1):
print(f" Term {i}: {term}")