diff options
author | inoas <mail@inoas.com> | 2022-10-27 20:47:12 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-27 21:47:12 +0100 |
commit | 6c9a956af844379aa8d33fa3832636b33493f776 (patch) | |
tree | be8da108d9481945c28979e25cda1143180655e8 | |
parent | e6401929ce83b332e05cc86db58e5d537b0ea87f (diff) | |
download | gleam_stdlib-6c9a956af844379aa8d33fa3832636b33493f776.tar.gz gleam_stdlib-6c9a956af844379aa8d33fa3832636b33493f776.zip |
add list.shuffle (#360)
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | src/gleam/list.gleam | 42 | ||||
-rw-r--r-- | test/gleam/list_test.gleam | 23 |
3 files changed, 66 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e60f82..215e54b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Fixed a bug where `regex.scan` would not work correctly on utf8. - The performance of `list.flatten` has been greatly improved. - The `string_builder` module gains the `join` function. +- The `list` module gains the `shuffle` function. ## v0.24.0 - 2022-10-15 diff --git a/src/gleam/list.gleam b/src/gleam/list.gleam index 04d311e..268642d 100644 --- a/src/gleam/list.gleam +++ b/src/gleam/list.gleam @@ -23,6 +23,7 @@ //// import gleam/int +import gleam/float import gleam/order.{Order} import gleam/pair @@ -1822,3 +1823,44 @@ pub fn transpose(list_of_list: List(List(a))) -> List(List(a)) { } } } + +fn do_shuffle_pair_unwrap(list: List(#(Float, a)), acc: List(a)) -> List(a) { + case list { + [] -> acc + _ -> { + let [elem_pair, ..enumerable] = list + do_shuffle_pair_unwrap(enumerable, [elem_pair.1, ..acc]) + } + } +} + +fn do_shuffle_by_pair_indexes( + list_of_pairs: List(#(Float, a)), +) -> List(#(Float, a)) { + sort( + list_of_pairs, + fn(a_pair: #(Float, a), b_pair: #(Float, a)) -> Order { + float.compare(a_pair.0, b_pair.0) + }, + ) +} + +/// Takes a list, randomly sorts all items and returns the shuffled list. +/// +/// ## Example +/// +/// ```gleam +/// list.range(1, 10) +/// |> list.shuffle() +/// > [1, 6, 9, 10, 3, 8, 4, 2, 7, 5] +/// ``` +/// +/// Notice: This function uses Erlang's `:rand` module or Javascript's +/// `Math.random()` to calcuate the index shuffling. +/// +pub fn shuffle(list: List(a)) -> List(a) { + list + |> fold(from: [], with: fn(acc, a) { [#(float.random(0.0, 1.0), a), ..acc] }) + |> do_shuffle_by_pair_indexes() + |> do_shuffle_pair_unwrap([]) +} diff --git a/test/gleam/list_test.gleam b/test/gleam/list_test.gleam index 13dbbcb..ec95af4 100644 --- a/test/gleam/list_test.gleam +++ b/test/gleam/list_test.gleam @@ -1081,3 +1081,26 @@ pub fn transpose_test() { list.transpose([[1, 2, 3], [101, 102], [201, 202, 203]]) |> should.equal([[1, 101, 201], [2, 102, 202], [3, 203]]) } + +pub fn shuffle_test() { + [] + |> list.shuffle + |> should.equal([]) + + [1, 1] + |> list.shuffle + |> should.equal([1, 1]) + + [1, 1, 1] + |> list.shuffle + |> should.equal([1, 1, 1]) + + list.range(1, 100) + |> list.shuffle + |> list.sort(int.compare) + |> should.equal(list.range(1, 100)) + + // TCO test + list.range(0, recursion_test_cycles) + |> list.shuffle() +} |