Skip to content

Add map and map_with_key Methods to Map #2210

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

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a9b3888
feat: add four new functions to HAMT and their tests
Asterless May 21, 2025
09b6a99
fix(union_with): fix union_with for HAMT,now it can handle branch
Asterless May 21, 2025
1b84483
feat(sparse_array): add intersection and difference methods
Asterless May 21, 2025
0cdca5b
fix(HAMT): fix union_with, intersection, intersection_with and differ…
Asterless May 21, 2025
44c0a79
feat(hashset): add intersection and difference methods to hashset
Asterless May 21, 2025
f80c9f2
commit other files
Asterless May 21, 2025
7f2524c
feat: add four new functions to HAMT and their tests
Asterless May 21, 2025
fc71f34
fix(union_with): fix union_with for HAMT,now it can handle branch
Asterless May 21, 2025
5adb5ce
feat(sparse_array): add intersection and difference methods
Asterless May 21, 2025
8d06b82
fix(HAMT): fix union_with, intersection, intersection_with and differ…
Asterless May 21, 2025
eb6ef82
feat(hashset): add intersection and difference methods to hashset
Asterless May 21, 2025
61ca5f0
Merge branch 'feature/20250522_HAMT' of github.com:Asterless/core int…
Asterless May 22, 2025
a0d7669
style: change the position of some function declarations
Asterless May 22, 2025
29c51a5
fix: fix formatting of the code
Asterless May 22, 2025
4b46d45
Merge pull request #1 from Asterless/feature/20250522_HAMT
Asterless May 22, 2025
256557a
Merge branch 'main' of github.com:Asterless/core
Asterless May 22, 2025
dab49f5
feat: Update the function declarations of hash tables and sparse arrays
Asterless May 22, 2025
5e13daf
WIP: save local changes
Asterless May 23, 2025
ab43a5d
Merge remote-tracking branch 'upstream/main'
Asterless May 23, 2025
dbc4d78
Merge branch 'main' of https://github.com/moonbitlang/core
Asterless May 23, 2025
90c7df6
feat: add map, map_with_key, filter, fold, and partition methods to M…
Asterless May 23, 2025
fa1ea23
refactor: update Map methods to simplify type parameters and improve …
Asterless May 23, 2025
b4dea64
Merge branch 'moonbitlang:main' into feature/map-enhancement
Asterless May 23, 2025
ec62c38
refactor: remove unnecessary blank lines in various implementations
Asterless Jun 5, 2025
3854e81
Refactor: moon info
Asterless Jun 5, 2025
f56e9c3
Merge https://github.com/moonbitlang/core
Asterless Jun 5, 2025
ece5ea6
Refactor: moon info
Asterless Jun 5, 2025
0e0c008
Merge branch 'feature/map-enhancement' of https://github.com/Asterles…
Asterless Jun 5, 2025
0c06668
Merge branch 'main' into feature/map-enhancement
Asterless Jun 5, 2025
b770156
Refactor: moon info
Asterless Jun 5, 2025
6191749
Merge branch 'feature/map-enhancement' of https://github.com/Asterles…
Asterless Jun 5, 2025
62d2892
Merge branch 'main' into feature/map-enhancement
Asterless Jun 6, 2025
5503bd2
Merge branch 'main' into feature/map-enhancement
Asterless Jun 6, 2025
6f8a2ea
Merge branch 'main' into feature/map-enhancement
Asterless Jun 7, 2025
31efccd
fix(Map): Delete the unnecessary error polymorphism functions
Asterless Jun 7, 2025
da59fcb
fix(Map): Remove the redundant blank lines
Asterless Jun 7, 2025
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
5 changes: 5 additions & 0 deletions builtin/builtin.mbti
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ fn[K : Hash + Eq, V] Map::contains(Self[K, V], K) -> Bool
fn[K : Hash + Eq, V : Eq] Map::contains_kv(Self[K, V], K, V) -> Bool
fn[K, V] Map::each(Self[K, V], (K, V) -> Unit?Error) -> Unit?Error
fn[K, V] Map::eachi(Self[K, V], (Int, K, V) -> Unit?Error) -> Unit?Error
fn[K : Hash + Eq, V] Map::filter(Self[K, V], (K, V) -> Bool) -> Self[K, V]
fn[K : Hash + Eq, V, A] Map::fold(Self[K, V], A, (A, K, V) -> A) -> A
fn[K : Hash + Eq, V] Map::from_array(Array[(K, V)]) -> Self[K, V]
fn[K : Hash + Eq, V] Map::from_iter(Iter[(K, V)]) -> Self[K, V]
fn[K : Hash + Eq, V] Map::get(Self[K, V], K) -> V?
Expand All @@ -266,11 +268,14 @@ fn[K, V] Map::is_empty(Self[K, V]) -> Bool
fn[K, V] Map::iter(Self[K, V]) -> Iter[(K, V)]
fn[K, V] Map::iter2(Self[K, V]) -> Iter2[K, V]
fn[K, V] Map::keys(Self[K, V]) -> Iter[K]
fn[K : Hash + Eq, V, V2] Map::map(Self[K, V], (V) -> V2) -> Self[K, V2]
fn[K : Hash + Eq, V, V2] Map::map_with_key(Self[K, V], (K, V) -> V2) -> Self[K, V2]
fn[K, V] Map::new(capacity~ : Int = ..) -> Self[K, V]
fn[K : Hash + Eq, V] Map::of(FixedArray[(K, V)]) -> Self[K, V]
#deprecated
fn[K : Hash + Eq, V] Map::op_get(Self[K, V], K) -> V?
fn[K : Hash + Eq, V] Map::op_set(Self[K, V], K, V) -> Unit
fn[K : Hash + Eq, V] Map::partition(Self[K, V], (K, V) -> Bool) -> (Self[K, V], Self[K, V])
fn[K : Hash + Eq, V] Map::remove(Self[K, V], K) -> Unit
fn[K : Hash + Eq, V] Map::set(Self[K, V], K, V) -> Unit
fn[K, V] Map::size(Self[K, V]) -> Int
Expand Down
82 changes: 82 additions & 0 deletions builtin/linked_hash_map.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -590,3 +590,85 @@ pub fn[K : Hash + Eq, V] Map::from_iter(iter : Iter[(K, V)]) -> Map[K, V] {
pub impl[K, V] Default for Map[K, V] with default() {
Map::new()
}

///|
/// Applies a function to each key-value pair in the map and returns a new map with the results.
pub fn[K : Hash + Eq, V, V2] Map::map(
self : Map[K, V],
f : (V) -> V2
) -> Map[K, V2] {
self.map_with_key(fn(_, v) { f(v) })
}

///|
/// Applies a function to each key-value pair in the map and returns a new map with the results, using the original keys.
pub fn[K : Hash + Eq, V, V2] Map::map_with_key(
self : Map[K, V],
f : (K, V) -> V2
) -> Map[K, V2] {
if self.is_empty() {
return Map::new()
}
let m = Map::new(capacity=self.size)
for e in self.iter() {
m.set(e.0, f(e.0, e.1))
}
m
}

///|
/// Filters the map by applying a predicate function to each key-value pair.
pub fn[K : Hash + Eq, V] Map::filter(
self : Map[K, V],
pred : (K, V) -> Bool
) -> Map[K, V] {
if self.is_empty() {
return Map::new()
}
let m = Map::new(capacity=self.size)
for e in self.iter() {
if pred(e.0, e.1) {
m.set(e.0, e.1)
}
}
m
}

///|
/// Folds the map from an initial value by applying a function to each key-value pair and the accumulator.
/// The order of folding is not guaranteed.
pub fn[K : Hash + Eq, V, A] Map::fold(
self : Map[K, V],
init : A,
f : (A, K, V) -> A
) -> A {
if self.is_empty() {
return init
}
let mut acc = init
for e in self {
acc = f(acc, e.0, e.1)
}
acc
}

///|
/// Partitions the map into two maps based on a predicate function.
pub fn[K : Hash + Eq, V] Map::partition(
self : Map[K, V],
pred : (K, V) -> Bool
) -> (Map[K, V], Map[K, V]) {
if self.is_empty() {
return (Map::new(), Map::new())
}
let m1 = Map::new(capacity=self.size)
let m2 = Map::new(capacity=self.size)
for e in self {
if pred(e.0, e.1) {
m1.set(e.0, e.1)
} else {
m2.set(e.0, e.1)
}
}
(m1, m2)
}
93 changes: 93 additions & 0 deletions immut/hashmap/HAMT_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,99 @@ test "HAMT::difference with branch" {
assert_eq!(diff.get(4), None)
}

///|
test "HAMT::intersection with empty" {
let m1 = @hashmap.of([(1, 1)])
let m2 = @hashmap.new()
assert_eq!(m1.intersection(m2).size(), 0)
assert_eq!(m2.intersection(m1).size(), 0)
}

///|
test "HAMT::intersection with leaf" {
let m1 = @hashmap.of([(1, 1), (2, 2)])
let m2 = @hashmap.singleton(2, 2)
let m3 = @hashmap.singleton(3, 3)
assert_eq!(m1.intersection(m2).get(2), Some(2))
assert_eq!(m1.intersection(m3).get(3), None)
assert_eq!(m2.intersection(m1).get(2), Some(2))
}

///|
test "HAMT::intersection with branch" {
let m1 = @hashmap.of([(1, 1), (2, 2), (3, 3)])
let m2 = @hashmap.of([(2, 2), (3, 30), (4, 4)])
let inter = m1.intersection(m2)
assert_eq!(inter.get(1), None)
assert_eq!(inter.get(2), Some(2))
assert_eq!(inter.get(3), Some(3))
assert_eq!(inter.get(4), None)
}

///|
test "HAMT::intersection_with with empty" {
let m1 = @hashmap.of([(1, 1)])
let m2 = @hashmap.new()
assert_eq!(m1.intersection_with(m2, fn(_k, v1, v2) { v1 + v2 }).size(), 0)
assert_eq!(m2.intersection_with(m1, fn(_k, v1, v2) { v1 + v2 }).size(), 0)
}

///|
test "HAMT::intersection_with with leaf" {
let m1 = @hashmap.of([(1, 1), (2, 2)])
let m2 = @hashmap.singleton(2, 20)
let m3 = @hashmap.singleton(3, 30)
assert_eq!(
m1.intersection_with(m2, fn(_k, v1, v2) { v1 + v2 }).get(2),
Some(22),
)
assert_eq!(m1.intersection_with(m3, fn(_k, v1, v2) { v1 + v2 }).get(3), None)
assert_eq!(
m2.intersection_with(m1, fn(_k, v1, v2) { v1 + v2 }).get(2),
Some(22),
)
}

///|
test "HAMT::intersection_with with branch" {
let m1 = @hashmap.of([(1, 1), (2, 2), (3, 3)])
let m2 = @hashmap.of([(2, 20), (3, 30), (4, 4)])
let inter = m1.intersection_with(m2, fn(_k, v1, v2) { v1 * v2 })
assert_eq!(inter.get(1), None)
assert_eq!(inter.get(2), Some(40))
assert_eq!(inter.get(3), Some(90))
assert_eq!(inter.get(4), None)
}

///|
test "HAMT::difference with empty" {
let m1 = @hashmap.of([(1, 1)])
let m2 = @hashmap.new()
assert_eq!(m1.difference(m2), m1)
assert_eq!(m2.difference(m1).size(), 0)
}

///|
test "HAMT::difference with leaf" {
let m1 = @hashmap.of([(1, 1), (2, 2)])
let m2 = @hashmap.singleton(2, 2)
let m3 = @hashmap.singleton(3, 3)
assert_eq!(m1.difference(m2).get(2), None)
assert_eq!(m1.difference(m3).get(1), Some(1))
assert_eq!(m2.difference(m1).size(), 0)
}

///|
test "HAMT::difference with branch" {
let m1 = @hashmap.of([(1, 1), (2, 2), (3, 3)])
let m2 = @hashmap.of([(2, 2), (3, 30), (4, 4)])
let diff = m1.difference(m2)
assert_eq!(diff.get(1), Some(1))
assert_eq!(diff.get(2), None)
assert_eq!(diff.get(3), None)
assert_eq!(diff.get(4), None)
}

///|
test "HAMT::each" {
let empty = @hashmap.new()
Expand Down