Skip to content
Open
Show file tree
Hide file tree
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
95 changes: 95 additions & 0 deletions src/gleam/list.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -1501,6 +1501,101 @@ fn range_loop(start: Int, stop: Int, acc: List(Int)) -> List(Int) {
}
}

/// Creates a list of ints ranging from a given start and finish with the given step.
///
/// Intended usage is from < to and positive step or from > to and negative step.
///
/// Edge cases:
/// If called with same from and to return one element list disregarding step.
/// Otherwise if called with step 0 returns empty list.
/// Otherwise from from < to and negative step returns empty list.
/// Otherwise from to < from and positive step returns empty list.
///
/// ## Examples
///
/// ```gleam
/// range_with_step(1, 5, 2)
/// // -> [1, 3, 5]
/// ```
///
/// ```gleam
/// range_with_step(1, 6, 2)
/// // -> [1, 3, 5]
/// ```
///
/// ```gleam
/// range_with_step(6, -1, -3)
/// // -> [6, 3, 0]
/// ```
///
/// ```gleam
/// range_with_step(6, -3, -3)
/// // -> [6, 3, 0, -3]
/// ```
///
/// ```gleam
/// range_with_step(123, 123, 0)
/// // -> [123]
/// ```
///
/// ```gleam
/// range_with_step(123, 999, 0)
/// // -> []
/// ```
///
/// ```gleam
/// range_with_step(123, 999, -1)
/// // -> []
/// ```
///
/// ```gleam
/// range_with_step(123, 100, 1)
/// // -> []
/// ```
///
pub fn range_with_step(
from start: Int,
to stop: Int,
step step: Int,
) -> List(Int) {
case int.compare(start, stop), step {
order.Eq, _ -> [start]
_, 0 -> []
order.Lt, x if x < 0 -> []
order.Gt, x if x > 0 -> []
order.Lt, _ -> range_with_step_positive_loop(start, stop, step, [])
order.Gt, _ -> range_with_step_negative_loop(start, stop, step, [])
}
}

fn range_with_step_positive_loop(
start: Int,
stop: Int,
step: Int,
acc: List(Int),
) -> List(Int) {
case int.compare(start, stop) {
order.Eq -> reverse([stop, ..acc])
order.Gt -> reverse(acc)
order.Lt ->
range_with_step_positive_loop(start + step, stop, step, [start, ..acc])
}
}

fn range_with_step_negative_loop(
start: Int,
stop: Int,
step: Int,
acc: List(Int),
) -> List(Int) {
case int.compare(start, stop) {
order.Eq -> reverse([stop, ..acc])
order.Gt ->
range_with_step_negative_loop(start + step, stop, step, [start, ..acc])
order.Lt -> reverse(acc)
}
}

/// Builds a list of a given value a given number of times.
///
/// ## Examples
Expand Down
22 changes: 22 additions & 0 deletions test/gleam/list_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,28 @@ pub fn range_test() {
list.range(1, recursion_test_cycles)
}

pub fn range_with_step_test() {
assert list.range_with_step(1, 5, 2) == [1, 3, 5]

assert list.range_with_step(1, 6, 2) == [1, 3, 5]

assert list.range_with_step(6, -1, -3) == [6, 3, 0]

assert list.range_with_step(6, -3, -3) == [6, 3, 0, -3]

assert list.range_with_step(123, 123, 0) == [123]

assert list.range_with_step(123, 999, 0) == []

assert list.range_with_step(123, 999, -1) == []

assert list.range_with_step(123, 100, 1) == []

// TCO tests
let _ = list.range_with_step(1, recursion_test_cycles * 2, 2)
list.range_with_step(1, -recursion_test_cycles * 2, -2)
}

pub fn repeat_test() {
assert list.repeat(1, -10) == []

Expand Down