aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorinoas <mail@inoas.com>2022-10-27 20:47:12 +0000
committerGitHub <noreply@github.com>2022-10-27 21:47:12 +0100
commit6c9a956af844379aa8d33fa3832636b33493f776 (patch)
treebe8da108d9481945c28979e25cda1143180655e8
parente6401929ce83b332e05cc86db58e5d537b0ea87f (diff)
downloadgleam_stdlib-6c9a956af844379aa8d33fa3832636b33493f776.tar.gz
gleam_stdlib-6c9a956af844379aa8d33fa3832636b33493f776.zip
add list.shuffle (#360)
-rw-r--r--CHANGELOG.md1
-rw-r--r--src/gleam/list.gleam42
-rw-r--r--test/gleam/list_test.gleam23
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()
+}