[EDIT: Already exists] Feature Request: Introduce scan

I've been toying around with AsyncBluetooth to update my handling of BLE peripherals using Concurrency rather than shudders delegates.

In transforming my old implementation of BLE peripheral discovery to one using an AsyncStream, I've run across the need to filter and accumulate the elements of an AsyncSequence into an Array and "emit" that array at regular intervals (in short: to emit a list of all distinct discovered peripherals with up-to-date RSSI). While most steps I've needed can be implemented with .compactMap, .filter, etc., I haven't found the equivalent of Combine/Rx's scan(_:_:) which would allow me to add new peripherals or update existing ones (based on UUID) with up-to-date RSSI. The closest match would be .throttle(for:reducing:) but AFAIK, the reduction happens on all elements emitted during the throttling interval, not all elements from the start.

So my suggestion: include a new AsyncScanSequence that allow me to do just what .scan(_:_:) does in Combine!

What do you think?

1 Like

I think this would be very useful, with one change: make the accumulator inout.

func scan<T>(
    _ initialResult: inout T,
    _ nextPartialResult: (inout T, Element) -> Void)

That way you could do essentially

let peers = newPeers.scan([]) { peers, newPeer in
    peers.append(newPeer)
}

This would avoid the copying that the Combine method incurs.

Shame on me, I did not read the docs carefully enough! It already exists as .reductions() provide reductions to a single value of the same type as the Base's Element as well as reductions to a new type, including both variants with and without inout.

Taken from the docs themselves:

Topic closed

6 Likes