-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Utility modules for lists and maps #18
Changes from 4 commits
453ebcb
d8e8f13
9c77dff
6b204ad
9aa5552
5514a53
b0a2942
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
module util::ListUtil | ||
|
||
import List; | ||
|
||
@synopsis{ | ||
Representation of a traversal direction along a list | ||
} | ||
|
||
data Direction // Traverse lists... | ||
= forward() // - ...from left to right; | ||
| backward() // - ...from right to left. | ||
; | ||
|
||
@synopsis{ | ||
Reorder a list according to the specified direction | ||
} | ||
|
||
list[&T] reorder(list[&T] l, forward()) = l; | ||
list[&T] reorder(list[&T] l, backward()) = reverse(l); | ||
|
||
@synopsis{ | ||
Removes multiple occurrences of elements in a list. The last occurrence | ||
remains (cf. `List::dup`). | ||
} | ||
|
||
list[&T] dupLast(list[&T] l) = reverse(dup(reverse(l))); // TODO: Optimize/avoid `reverse`-ing? | ||
|
||
@synopsis{ | ||
Checks if list `l1` is a strict prefix of list `l2` | ||
} | ||
|
||
bool isStrictPrefix(list[&T] l1, list[&T] l2) | ||
= size(l1) < size(l2) && !any(i <- [0..size(l1)], l1[i] != l2[i]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ps, in the challenge:
is even shorter ;) Or even this ;)
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's brilliant, I concede 😉 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I got a bit interested about performance of the various implementations (not really relevant for the current use case; just out of curiosity) and took a few anecdotal measurements. For posterity, here it goes... Implementationsbool isStrictPrefix1([], [])
= false;
bool isStrictPrefix1([], [_, *_])
= true;
bool isStrictPrefix1([_, *_], [])
= false;
bool isStrictPrefix1([head1, *tail1], [head2, *tail2])
= head1 == head2 && isStrictPrefix1(tail1, tail2);
// -------------------------------------------------------------------------- //
bool isStrictPrefix2(list[&T] l1, list[&T] l2) {
if (size(l1) >= size(l2)) {
return false;
}
if (i <- [0..size(l1)], l1[i] != l2[i]) {
return false;
}
return true;
}
// -------------------------------------------------------------------------- //
bool isStrictPrefix3(list[&T] l1, list[&T] l2)
= size(l1) < size(l2) && !any(i <- [0..size(l1)], l1[i] != l2[i]);
// -------------------------------------------------------------------------- //
bool isStrictPrefix4(list[&T] l1, list[&T] l2)
= size(l1) < size(l2) && l1 == l2[..size(l1)];
// -------------------------------------------------------------------------- //
bool isStrictPrefix5(list[&T] l1:[_,*_], [*l1, _, *_]) = true;
default bool isStrictPrefix5(_, _) = false; Measurementsimport IO;
import util::Benchmark;
void main(int i = 0) {
cases = (
"v1": void() { for (_ <- [0..1000]) { isStrictPrefix1([0..i], [0..1000]); } },
"v2": void() { for (_ <- [0..1000]) { isStrictPrefix2([0..i], [0..1000]); } },
"v3": void() { for (_ <- [0..1000]) { isStrictPrefix3([0..i], [0..1000]); } },
"v4": void() { for (_ <- [0..1000]) { isStrictPrefix4([0..i], [0..1000]); } },
"v5": void() { for (_ <- [0..1000]) { isStrictPrefix5([0..i], [0..1000]); } }
);
println(benchmark(cases));
} QuizQuestion: Which implementation is slowest?Answer...
Question: Which implementation is fastest?Answer...
Question: Which implementation crashes, if any?Answer...
ResultsFirst seriesWith
Second seriesWithout
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Micro-benchmarks are hard ;) these are doing to much in the loop that is not part of the focus. On my machine, I get these numbers:
and after rewriting the benchmark:
it prints:
suddenly v5 is the fastest, and the numbers are all quite a bit lower, let's increase the rounds to 100000.
so yeah, v5 might be a quite a bit faster than the rest of them ;) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you, that's interesting! 🙂 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Although I would have kept V4 for readability ;) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module util::MapUtil | ||
|
||
@synopsis{ | ||
Updates the mapping of each key `k` in map of lists `m` to be the union of: | ||
(1) the existing list `m[k]`, and (2) the new elements-to-be-inserted | ||
`values[k]`. For instance: | ||
- m = ("foo": [1, 2, 3], "bar": [], "baz": [1, 2]) | ||
- values = ("foo": [4, 5], "bar": [123], "qux": [3, 4]) | ||
- return = ("foo": [1, 2, 3, 4, 5], "bar": [123], "baz": [1, 2]) | ||
} | ||
|
||
map[&K, list[&V]] insertIn(map[&K, list[&V]] m, map[&K, &V] values) | ||
= (k: m[k] + (k in values ? [values[k]] : []) | k <- m); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code has become unused and is just removed