Skip to content

maps: add iterator-related functions #61900

Closed
@rsc

Description

@rsc

We propose to add the following functions to package maps, to provide good support for code using iterators.

This is one of a collection of proposals updating the standard library for the new 'range over function' feature (#61405). It would only be accepted if that proposal is accepted. See #61897 for a list of related proposals.

All serves as a “source” for iterators.

// All returns an iterator over key-value pairs from m.
func All[Map ~map[K]V, K comparable, V any](m Map) iter.Seq2[K, V] {
	return func(yield func(K, V) bool) bool {
		for k, v := range m {
			if !yield(k, v) {
				return false
			}
		}
		return true
	}
}

Keys and Values are like All: not terribly useful by themselves but useful as inputs to other iteration adapters.
In particular, we expect that x := slices.Sorted(maps.Keys(m)) will be a common pattern.

// Keys returns an iterator over keys in m.
func Keys[Map ~map[K]V, K comparable, V any](m Map) iter.Seq[K] {
	return func(yield func(K) bool) bool {
		for k := range m {
			if !yield(k) {
				return false
			}
		}
		return true
	}
}
// Values returns an iterator over values in m.
func Values[Map ~map[K]V, K comparable, V any](m Map) iter.Seq[V] {
	return func(yield func(V) bool) bool {
		for _, v := range m {
			if !yield(v) {
				return false
			}
		}
		return true
	}
}

Insert and Collect serve as “sinks” for iterators.

// Insert adds the key-value pairs from seq to m.
func Insert[Map ~map[K]V, K comparable, V any](m M, seq iter.Seq2[K, V]) {
	for k, v := range seq {
		m[k] = v
	}
	return m
}
// Collect collects key-value pairs from seq into a new map
// and returns it.
func Collect[K comparable, V any](seq iter.Seq2[K, V]) map[K]V {
	m := make(map[K]V)
	Insert(m, seq)
	return m
}

Activity

added this to the Proposal milestone on Aug 9, 2023
moved this to Incoming in Proposalson Aug 9, 2023
rsc

rsc commented on Aug 9, 2023

@rsc
ContributorAuthor

This proposal has been added to the active column of the proposals project
and will now be reviewed at the weekly proposal review meetings.
— rsc for the proposal review group

moved this from Incoming to Active in Proposalson Aug 9, 2023
rsc

rsc commented on Aug 30, 2023

@rsc
ContributorAuthor

Finishing this proposal discussion is blocked on #61405.

gopherbot

gopherbot commented on Jan 26, 2024

@gopherbot
Contributor

Change https://go.dev/cl/558736 mentions this issue: maps: add All, Keys, Values, Insert, Collect

earthboundkid

earthboundkid commented on Jan 30, 2024

@earthboundkid
Contributor

It is unfortunate that slices.Sorted(maps.Keys(m)) won't get a length hint from m and may end up doing unnecessary allocations and copies. What if there were also maps.SortedKeys(m) that did the right thing?

Merovius

Merovius commented on Jan 30, 2024

@Merovius
Contributor

@earthboundkid ISTM if that is a concern, it should maybe rather be slices.SortedLength[E any](int, iter.Seq[E]) (modulo name), as any use of "make a sorted slice from an iterator" would suffer the same issue.

I get, FWIW, that "get the sorted keys from a map" is a fairly common use case, to try and get deterministic order from the specifically non-deterministic maps. But it still seems a more general problem.

gophun

gophun commented on Jan 30, 2024

@gophun

maps.Keys could return a sequence implementation with a length hint and slices.Sorted could type assert for that, similar to what some io.Reader functions do.

gophun

gophun commented on Jan 30, 2024

@gophun

Nevermind, iter.Seq is a concrete type, not an interface.

51 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Development

      Participants

      @rsc@magical@andig@earthboundkid@DeedleFake

      Issue actions

        maps: add iterator-related functions · Issue #61900 · golang/go