Skip to content

Commit c17ef52

Browse files
pendletonglpil
authored andcommitted
feat: optimised version of permutations
Rewrote permutations using a zipper method which results in around a 1.8x speedup and over 1.5x memory usage reduction
1 parent e1ffe34 commit c17ef52

File tree

1 file changed

+29
-13
lines changed

1 file changed

+29
-13
lines changed

src/gleam/list.gleam

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ pub fn reverse(list: List(a)) -> List(a) {
136136
/// This function runs in linear time, proportional to the length of the list
137137
/// to prepend.
138138
///
139+
@external(erlang, "lists", "reverse")
139140
fn reverse_and_prepend(list prefix: List(a), to suffix: List(a)) -> List(a) {
140141
case prefix {
141142
[] -> suffix
@@ -1834,19 +1835,34 @@ fn partition_loop(list, categorise, trues, falses) {
18341835
pub fn permutations(list: List(a)) -> List(List(a)) {
18351836
case list {
18361837
[] -> [[]]
1837-
[_, ..] ->
1838-
index_map(list, fn(i, i_idx) {
1839-
index_fold(list, [], fn(acc, j, j_idx) {
1840-
case i_idx == j_idx {
1841-
True -> acc
1842-
False -> [j, ..acc]
1843-
}
1844-
})
1845-
|> reverse
1846-
|> permutations
1847-
|> map(fn(permutation) { [i, ..permutation] })
1848-
})
1849-
|> flatten
1838+
l -> zipper(l, [], [])
1839+
}
1840+
}
1841+
1842+
fn zipper(l: List(a), r: List(a), acc: List(List(a))) -> List(List(a)) {
1843+
case l {
1844+
[] -> reverse(acc)
1845+
[h, ..rest] ->
1846+
zipprepend(
1847+
h,
1848+
permutations(reverse_and_prepend(r, rest)),
1849+
rest,
1850+
[h, ..r],
1851+
acc,
1852+
)
1853+
}
1854+
}
1855+
1856+
fn zipprepend(
1857+
el: a,
1858+
l1: List(List(a)),
1859+
l2: List(a),
1860+
l3: List(a),
1861+
acc: List(List(a)),
1862+
) -> List(List(a)) {
1863+
case l1 {
1864+
[] -> zipper(l2, l3, acc)
1865+
[h, ..rest] -> zipprepend(el, rest, l2, l3, [[el, ..h], ..acc])
18501866
}
18511867
}
18521868

0 commit comments

Comments
 (0)