Skip to content

Commit 98faaac

Browse files
committed
Add FromFuncs()
1 parent efc6ea0 commit 98faaac

File tree

2 files changed

+87
-24
lines changed

2 files changed

+87
-24
lines changed

maps.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,27 @@ func FromSlices[K comparable, V any](keys []K, values []V) map[K]V {
142142
return m
143143
}
144144

145+
// FromFuncs makes a map from the return values of two functions (e.g. from math.random).
146+
// Panics if the keys functions is nil or size is negative.
147+
// If the values function is nil, the zero value of type V will be used for all values.
148+
func FromFuncs[K comparable, V any](size int, keys func() K, values func() V) map[K]V {
149+
if size < 0 {
150+
panic("size must be >= 0")
151+
}
152+
if keys == nil {
153+
panic("nil functions")
154+
}
155+
m := make(map[K]V, size)
156+
for i := 0; i < size; i++ {
157+
var v V
158+
if values != nil {
159+
v = values()
160+
}
161+
m[keys()] = v
162+
}
163+
return m
164+
}
165+
145166
// KeysForValue returns a slice with keys which have the given value.
146167
func KeysForValue[K, V comparable](m map[K]V, value V) []K {
147168
return KeysForValueFunc(m, value, func(v1 V, v2 V) bool {

maps_test.go

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ func TestClone(t *testing.T) {
1313
{"a": 1},
1414
{"a": 1, "b": 2},
1515
}
16-
for _, test := range tests {
16+
for i, test := range tests {
1717
got := Clone(test)
1818
if !reflect.DeepEqual(got, test) {
19-
t.Errorf("got %v, want %v", got, test)
19+
t.Errorf("%d: got %v, want %v", i, got, test)
2020
}
2121
}
2222
}
@@ -28,10 +28,10 @@ func TestUpdate(t *testing.T) {
2828
{map[string]int{}, map[string]int{"a": 1}, map[string]int{"a": 1}},
2929
{map[string]int{"a": 1}, map[string]int{"a": 1, "b": 2}, map[string]int{"a": 1, "b": 2}},
3030
}
31-
for _, test := range tests {
31+
for i, test := range tests {
3232
Update(test.m1, test.m2)
3333
if !reflect.DeepEqual(test.m1, test.want) {
34-
t.Errorf("got %v, want %v", test.m1, test.want)
34+
t.Errorf("%d: got %v, want %v", i, test.m1, test.want)
3535
}
3636
}
3737
}
@@ -56,10 +56,10 @@ func TestClear(t *testing.T) {
5656
t.Errorf("got %v, want nil map", m)
5757
}
5858
want := map[string]int{}
59-
for _, test := range tests {
59+
for i, test := range tests {
6060
Clear(test)
6161
if !reflect.DeepEqual(test, want) {
62-
t.Errorf("got %v, want empty map", test)
62+
t.Errorf("%d: got %v, want empty map", i, test)
6363
}
6464
}
6565
}
@@ -74,9 +74,9 @@ func TestContains(t *testing.T) {
7474
{map[string]int{"a": 1}, true},
7575
{map[string]int{"b": 2}, false},
7676
}
77-
for _, test := range tests {
77+
for i, test := range tests {
7878
if got := Contains(test.m, "a"); got != test.want {
79-
t.Errorf("got %v, want %v", got, test.want)
79+
t.Errorf("%d: got %v, want %v", i, got, test.want)
8080
}
8181
}
8282
}
@@ -93,9 +93,9 @@ func TestGet(t *testing.T) {
9393
{map[string]int{key: 1}, 1},
9494
{map[string]int{"b": 2}, dflt},
9595
}
96-
for _, test := range tests {
96+
for i, test := range tests {
9797
if got := Get(test.m, key, dflt); got != test.want {
98-
t.Errorf("got %d, want %d", got, test.want)
98+
t.Errorf("%d: got %d, want %d", i, got, test.want)
9999
}
100100
}
101101
}
@@ -110,11 +110,11 @@ func TestKeys(t *testing.T) {
110110
{map[string]int{"a": 1}, []string{"a"}},
111111
{map[string]int{"a": 1, "b": 2}, []string{"a", "b"}},
112112
}
113-
for _, test := range tests {
113+
for i, test := range tests {
114114
got := Keys(test.m)
115115
sort.Slice(got, func(i, j int) bool { return got[i] < got[j] })
116116
if !reflect.DeepEqual(got, test.want) {
117-
t.Errorf("got %v, want %v", got, test.want)
117+
t.Errorf("%d: got %v, want %v", i, got, test.want)
118118
}
119119
}
120120
}
@@ -129,11 +129,11 @@ func TestValues(t *testing.T) {
129129
{map[string]int{"a": 1}, []int{1}},
130130
{map[string]int{"a": 1, "b": 2}, []int{1, 2}},
131131
}
132-
for _, test := range tests {
132+
for i, test := range tests {
133133
got := Values(test.m)
134134
sort.Slice(got, func(i, j int) bool { return got[i] < got[j] })
135135
if !reflect.DeepEqual(got, test.want) {
136-
t.Errorf("got %v, want %v", got, test.want)
136+
t.Errorf("%d: got %v, want %v", i, got, test.want)
137137
}
138138
}
139139
}
@@ -152,11 +152,11 @@ func TestEqual(t *testing.T) {
152152
{map[string]int{"a": 1, "b": 2}, map[string]int{"a": 1, "b": 2}, true},
153153
{map[string]int{"a": 1, "b": 2}, map[string]int{"b": 2, "a": 1}, true},
154154
}
155-
for _, test := range tests {
155+
for i, test := range tests {
156156
got1 := Equal(test.m1, test.m2)
157157
got2 := Equal(test.m2, test.m1)
158158
if got1 != test.want || got2 != test.want {
159-
t.Errorf("got %v and %v, want %v", got1, got2, test.want)
159+
t.Errorf("%d: got %v and %v, want %v", i, got1, got2, test.want)
160160
}
161161
}
162162
}
@@ -171,11 +171,11 @@ func TestItems(t *testing.T) {
171171
{map[string]int{"a": 1}, []Item[string, int]{{"a", 1}}},
172172
{map[string]int{"a": 1, "b": 2}, []Item[string, int]{{"a", 1}, {"b", 2}}},
173173
}
174-
for _, test := range tests {
174+
for i, test := range tests {
175175
got := Items(test.m)
176176
sort.Slice(got, func(i, j int) bool { return got[i].Key < got[j].Key })
177177
if !reflect.DeepEqual(got, test.want) {
178-
t.Errorf("got %v, want %v", got, test.want)
178+
t.Errorf("%d: got %v, want %v", i, got, test.want)
179179
}
180180
}
181181
}
@@ -190,9 +190,9 @@ func TestFromItems(t *testing.T) {
190190
{[]Item[string, int]{{"a", 1}}, map[string]int{"a": 1}},
191191
{[]Item[string, int]{{"a", 1}, {"b", 2}}, map[string]int{"a": 1, "b": 2}},
192192
}
193-
for _, test := range tests {
193+
for i, test := range tests {
194194
if got := FromItems(test.items); !reflect.DeepEqual(got, test.want) {
195-
t.Errorf("got %v, want %v", got, test.want)
195+
t.Errorf("%d: got %v, want %v", i, got, test.want)
196196
}
197197
}
198198
}
@@ -211,13 +211,55 @@ func TestFromSlices(t *testing.T) {
211211
{[]string{"a", "b"}, []int{1, 2}, map[string]int{"a": 1, "b": 2}},
212212
{[]string{"a", "b"}, []int{1, 2, 3}, map[string]int{"a": 1, "b": 2}},
213213
}
214-
for _, test := range tests {
214+
for i, test := range tests {
215215
if got := FromSlices(test.keys, test.values); !reflect.DeepEqual(got, test.want) {
216-
t.Errorf("got %v, want %v", got, test.want)
216+
t.Errorf("%d: got %v, want %v", i, got, test.want)
217217
}
218218
}
219219
}
220220

221+
func TestFromFuncs(t *testing.T) {
222+
first := true
223+
keyFn := func() string {
224+
if first {
225+
first = false
226+
return "a"
227+
}
228+
return "b"
229+
}
230+
valFn := func() int { return 1 }
231+
var tests = []struct {
232+
size int
233+
valF func() int
234+
want map[string]int
235+
}{
236+
{0, valFn, map[string]int{}},
237+
{1, valFn, map[string]int{"a": 1}},
238+
{2, valFn, map[string]int{"a": 1, "b": 1}},
239+
{0, nil, map[string]int{}},
240+
{1, nil, map[string]int{"a": 0}},
241+
{2, nil, map[string]int{"a": 0, "b": 0}},
242+
}
243+
for i, test := range tests {
244+
first = true
245+
if got := FromFuncs(test.size, keyFn, test.valF); !reflect.DeepEqual(got, test.want) {
246+
t.Errorf("%d: got %#v, want %#v", i, got, test.want)
247+
}
248+
}
249+
}
250+
251+
func TestFromFuncsNegSize(t *testing.T) {
252+
defer func() { _ = recover() }()
253+
FromFuncs(-1, func() string { return "a" }, func() int { return 1 })
254+
t.Error("did not panic")
255+
}
256+
257+
func TestFromFuncsNilKeys(t *testing.T) {
258+
defer func() { _ = recover() }()
259+
FromFuncs[string](1, nil, func() int { return 1 })
260+
t.Error("did not panic")
261+
}
262+
221263
func TestKeysForValue(t *testing.T) {
222264
value := 1
223265
var tests = []struct {
@@ -230,11 +272,11 @@ func TestKeysForValue(t *testing.T) {
230272
{map[string]int{"a": 1, "b": 2}, []string{"a"}},
231273
{map[string]int{"a": 1, "b": 2, "c": 1}, []string{"a", "c"}},
232274
}
233-
for _, test := range tests {
275+
for i, test := range tests {
234276
got := KeysForValue(test.m, value)
235277
sort.Slice(got, func(i, j int) bool { return got[i] < got[j] })
236278
if !reflect.DeepEqual(got, test.want) {
237-
t.Errorf("got %v, want %v", got, test.want)
279+
t.Errorf("%d: got %v, want %v", i, got, test.want)
238280
}
239281
}
240282
}

0 commit comments

Comments
 (0)