Skip to content

Commit bcc1277

Browse files
committed
maps: add All, Keys, Values, Insert, Collect
Fixed #61900.
1 parent e7bf995 commit bcc1277

File tree

7 files changed

+194
-2
lines changed

7 files changed

+194
-2
lines changed

api/next/61900.txt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pkg maps, func All[$0 interface{ ~map[$1]$2 }, $1 comparable, $2 interface{}]($0) iter.Seq2 #61900
2+
pkg maps, func Collect[$0 comparable, $1 interface{}](iter.Seq2) map[$0]$1 #61900
3+
pkg maps, func Insert[$0 interface{ ~map[$1]$2 }, $1 comparable, $2 interface{}]($0, iter.Seq2) #61900
4+
pkg maps, func Keys[$0 interface{ ~map[$1]$2 }, $1 comparable, $2 interface{}]($0) iter.Seq #61900
5+
pkg maps, func Values[$0 interface{ ~map[$1]$2 }, $1 comparable, $2 interface{}]($0) iter.Seq #61900

doc/next/6-stdlib/3-iter.md

+8
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,11 @@ with iterators:
2121
but uses a stable sort algorithm.
2222
- [Chunk](/pkg/slices#Chunk) returns an iterator over consecutive
2323
sub-slices of up to n elements of a slice.
24+
25+
The [`maps` package](/pkg/maps/) adds several functions that work
26+
with iterators:
27+
- [All](/pkg/maps#All) returns an iterator over key-value pairs from m.
28+
- [Keys](/pkg/maps#Keys) returns an iterator over keys in m.
29+
- [Values](/pkg/maps#Values) returns an iterator over values in m.
30+
- [Insert](/pkg/maps#Insert) adds the key-value pairs from seq to m.
31+
- [Collect](/pkg/maps#Collect) collects key-value pairs from seq into a new map and returns it.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<!-- see ../../3-iter.md -->

src/cmd/dist/test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ func (t *tester) registerTests() {
713713

714714
// GOEXPERIMENT=rangefunc tests
715715
if !t.compileOnly {
716-
for _, pkg := range []string{"iter", "slices"} {
716+
for _, pkg := range []string{"iter", "slices", "maps"} {
717717
t.registerTest("GOEXPERIMENT=rangefunc",
718718
&goTest{
719719
variant: pkg,

src/go/build/deps_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ var depsRules = `
5555
5656
internal/byteorder, internal/goarch, unsafe < internal/chacha8rand;
5757
58-
unsafe < internal/cpu, maps;
58+
unsafe < internal/cpu;
5959
6060
# RUNTIME is the core runtime group of packages, all of them very light-weight.
6161
internal/abi,
@@ -89,6 +89,9 @@ var depsRules = `
8989
< iter
9090
< RUNTIME;
9191
92+
RUNTIME, unsafe
93+
< maps;
94+
9295
# slices depends on unsafe for overlapping check, cmp for comparison
9396
# semantics, and math/bits for # calculating bitlength of numbers.
9497
RUNTIME, unsafe, cmp, math/bits

src/maps/iter.go

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package maps
6+
7+
import "iter"
8+
9+
// All returns an iterator over key-value pairs from m.
10+
func All[Map ~map[K]V, K comparable, V any](m Map) iter.Seq2[K, V] {
11+
return func(yield func(K, V) bool) {
12+
for k, v := range m {
13+
if !yield(k, v) {
14+
return
15+
}
16+
}
17+
}
18+
}
19+
20+
// Keys returns an iterator over keys in m.
21+
func Keys[Map ~map[K]V, K comparable, V any](m Map) iter.Seq[K] {
22+
return func(yield func(K) bool) {
23+
for k := range m {
24+
if !yield(k) {
25+
return
26+
}
27+
}
28+
}
29+
}
30+
31+
// Values returns an iterator over values in m.
32+
func Values[Map ~map[K]V, K comparable, V any](m Map) iter.Seq[V] {
33+
return func(yield func(V) bool) {
34+
for _, v := range m {
35+
if !yield(v) {
36+
return
37+
}
38+
}
39+
}
40+
}
41+
42+
// Insert adds the key-value pairs from seq to m.
43+
func Insert[Map ~map[K]V, K comparable, V any](m Map, seq iter.Seq2[K, V]) {
44+
for k, v := range seq {
45+
m[k] = v
46+
}
47+
}
48+
49+
// Collect collects key-value pairs from seq into a new map
50+
// and returns it.
51+
func Collect[K comparable, V any](seq iter.Seq2[K, V]) map[K]V {
52+
m := make(map[K]V)
53+
Insert(m, seq)
54+
return m
55+
}

src/maps/iter_test.go

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package maps
6+
7+
import (
8+
"slices"
9+
"testing"
10+
)
11+
12+
func TestAll(t *testing.T) {
13+
for size := 0; size < 10; size++ {
14+
m := make(map[int]int)
15+
for i := range size {
16+
m[i] = i
17+
}
18+
cnt := 0
19+
for i, v := range All(m) {
20+
v1, ok := m[i]
21+
if !ok || v != v1 {
22+
t.Errorf("at iteration %d got %d, %d want %d, %d", cnt, i, v, i, v1)
23+
}
24+
cnt++
25+
}
26+
if cnt != size {
27+
t.Errorf("read %d values expected %d", cnt, size)
28+
}
29+
}
30+
}
31+
32+
func TestKeys(t *testing.T) {
33+
for size := 0; size < 10; size++ {
34+
var want []int
35+
m := make(map[int]int)
36+
for i := range size {
37+
m[i] = i
38+
want = append(want, i)
39+
}
40+
41+
var got1 []int
42+
for k := range Keys(m) {
43+
got1 = append(got1, k)
44+
}
45+
slices.Sort(got1)
46+
if !slices.Equal(got1, want) {
47+
t.Errorf("Keys(%v) = %v, want %v", m, got1, want)
48+
}
49+
}
50+
}
51+
52+
func TestValues(t *testing.T) {
53+
for size := 0; size < 10; size++ {
54+
var want []int
55+
m := make(map[int]int)
56+
for i := range size {
57+
m[i] = i
58+
want = append(want, i)
59+
}
60+
61+
var got1 []int
62+
for v := range Values(m) {
63+
got1 = append(got1, v)
64+
}
65+
slices.Sort(got1)
66+
if !slices.Equal(got1, want) {
67+
t.Errorf("Values(%v) = %v, want %v", m, got1, want)
68+
}
69+
}
70+
}
71+
72+
func testSeq(yield func(int, int) bool) {
73+
for i := 0; i < 10; i += 2 {
74+
if !yield(i, i+1) {
75+
return
76+
}
77+
}
78+
}
79+
80+
var testSeqResult = map[int]int{
81+
0: 1,
82+
2: 3,
83+
4: 5,
84+
6: 7,
85+
8: 9,
86+
}
87+
88+
func TestInsert(t *testing.T) {
89+
got := map[int]int{
90+
1: 1,
91+
2: 1,
92+
}
93+
Insert(got, testSeq)
94+
95+
want := map[int]int{
96+
1: 1,
97+
2: 1,
98+
}
99+
for i, v := range testSeqResult {
100+
want[i] = v
101+
}
102+
103+
if !Equal(got, want) {
104+
t.Errorf("got %v, want %v", got, want)
105+
}
106+
}
107+
108+
func TestCollect(t *testing.T) {
109+
m := map[int]int{
110+
0: 1,
111+
2: 3,
112+
4: 5,
113+
6: 7,
114+
8: 9,
115+
}
116+
got := Collect(All(m))
117+
if !Equal(got, m) {
118+
t.Errorf("got %v, want %v", got, m)
119+
}
120+
}

0 commit comments

Comments
 (0)