Skip to content

proposal: maps: add Diff, Intersect, CopyFunc, Filter funcs #68480

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

Open
idsulik opened this issue Jul 17, 2024 · 14 comments
Open

proposal: maps: add Diff, Intersect, CopyFunc, Filter funcs #68480

idsulik opened this issue Jul 17, 2024 · 14 comments
Labels
Milestone

Comments

@idsulik
Copy link

idsulik commented Jul 17, 2024

I want to propose adding new functions to the maps package:

// CopyFunc is like Copy, but calls the conflict function to resolve duplicate keys.
func CopyFunc[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](m1 M1, m2 M2, conflict func(K, V, V) V) {
	for k, v := range m2 {
		if v1, ok := m1[k]; ok {
			m1[k] = conflict(k, v1, v)
		} else {
			m1[k] = v
		}
	}
}

// Filter creates a new map containing only the key-value pairs that match a predicate
func Filter[M ~map[K]V, K comparable, V any](m M, keep func(K, V) bool) M {
	m2 := make(M, len(m))
	for k, v := range m {
		if keep(k, v) {
			m2[k] = v
		}
	}
	return m2
}

// Diff returns a new map containing key-value pairs present in the first map but not in the second.
func Diff[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](m1 M1, m2 M2) M1 {
	m3 := make(M1, len(m1))
	for k, v := range m1 {
		if _, ok := m2[k]; !ok {
			m3[k] = v
		}
	}
	return m3
}

// Intersect returns a new map containing key-value pairs present in both maps.
func Intersect[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](m1 M1, m2 M2) M1 {
	m3 := make(M1, len(m1))
	for k, v := range m1 {
		if _, ok := m2[k]; ok {
			m3[k] = v
		}
	}
	return m3
}

I'll be happy to contribute a PR with tests if this is a good idea.

@gabyhelp
Copy link

Related Issues and Documentation

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

@idsulik idsulik changed the title maps: add Merge, MergeFunc, Filter funcs maps: add Diff, Intersect, Merge, MergeFunc, Filter funcs Jul 17, 2024
@gophun
Copy link

gophun commented Jul 17, 2024

How is Merge different from Copy?

@idsulik
Copy link
Author

idsulik commented Jul 17, 2024

How is Merge different from Copy?

You're right, they're the same, I think we can keep MergeFunc, but replace it with CopyFunc so we can resolve key conflicts

@idsulik idsulik changed the title maps: add Diff, Intersect, Merge, MergeFunc, Filter funcs maps: add Diff, Intersect, MergeFunc, Filter funcs Jul 17, 2024
@idsulik idsulik changed the title maps: add Diff, Intersect, MergeFunc, Filter funcs maps: add Diff, Intersect, CopyFunc, Filter funcs Jul 17, 2024
@jimmyfrasche
Copy link
Member

See the discussion for a generic set type: #47331 (possibly to be revived soon once iterators land in the next version, as that's what stalled the original discussion)

I also wrote https://pkg.go.dev/github.com/jimmyfrasche/mapset for doing set like things with regular maps

@ianlancetaylor ianlancetaylor changed the title maps: add Diff, Intersect, CopyFunc, Filter funcs proposal: maps: add Diff, Intersect, CopyFunc, Filter funcs Jul 17, 2024
@gopherbot gopherbot added this to the Proposal milestone Jul 17, 2024
@ianlancetaylor ianlancetaylor moved this to Incoming in Proposals Jul 17, 2024
@ianlancetaylor
Copy link
Contributor

Filter seems like something for #61898. I don't see why we need a maps-specific filter.

@idsulik
Copy link
Author

idsulik commented Jul 17, 2024

Filter seems like something for #61898. I don't see why we need a maps-specific filter.

The most important and useful are Diff and Intersect.
Filter will be useful for example, if you create map of files using some external package and you need to exclude some files from the map, or you create some items counter map and need to exclude items with less than 10 count

@ianlancetaylor
Copy link
Contributor

I'm not saying that Filter is not useful. I'm saying that the Filter2 from #61898 is fine, and we don't also need a separate maps.Filter.

@isgj
Copy link

isgj commented Jul 17, 2024

The most important and useful are Diff and Intersect.

The first thing that I thought when reading the title was how will you compare the values.
I think the documentation should mention that only the keys of the maps are used for comparison. IMHO these are not natural operations of maps.

@idsulik
Copy link
Author

idsulik commented Jul 18, 2024

I'm not saying that Filter is not useful. I'm saying that the Filter2 from #61898 is fine, and we don't also need a separate maps.Filter.

the filter allows you to filter only based on value, this one will also provide you key

@idsulik
Copy link
Author

idsulik commented Jul 18, 2024

I think the documentation should mention that only the keys of the maps are used for comparison

We can add value checking as well, if key is not found or values are diff, then append it to result map

@ianlancetaylor
Copy link
Contributor

the filter allows you to filter only based on value, this one will also provide you key

Filter2 filters based on both value and key.

@idsulik
Copy link
Author

idsulik commented Jul 18, 2024

Filter2 filters based on both value and key.

You're right, I missed it. so I think I can implement Diff and Intersect

@isgj
Copy link

isgj commented Jul 19, 2024

We can add value checking as well, if key is not found or values are diff

How will you compare the values? Or will you restrict the type constraint of V to comparable?

@idsulik
Copy link
Author

idsulik commented Jul 19, 2024

Or will you restrict the type constraint of V to comparable?

I see only this way for this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Incoming
Development

No branches or pull requests

7 participants