attach

Empareja cada valor con lo que derivas de él — la entrada se queda junto a su resultado.

Iterable<(A, B)> attach<A, B>(B Function(A a) f, Iterable<A> iterable) FxAsyncIterable<(A, B)> attachAsync<A, B>(FutureOr<B> Function(A a) f, FxAsyncIterable<A> iterable) Fx<(T, R)> Fx<T>.attach<R>(R Function(T a) f) // chain (sync) FxAsync<(T, R)> FxAsync<T>.attach<R>(FutureOr<R> Function(T a) f) // chain (async)

Lección

map reemplaza cada valor por su resultado — y en cuanto necesitas la entrada otra vez aguas abajo (para un respaldo, para etiquetar, para loguear), te encuentras construyendo registros a mano: .map((x) async => (x, await f(x))). attach(f) es ese idioma como operador: produce pares (valor, f(valor)), perezosamente.

Donde se gana el sueldo es en las cadenas async. Busca un precio por artículo y el par mantiene el artículo junto al precio (quizá ausente), de modo que el respaldo r.$2 ?? r.$1.listPrice y la etiqueta «¿de qué SKU era esto?» siguen al alcance. La forma async está construida sobre mapAsync, así que es segura en paralelo — pon concurrent(n) después y corren n búsquedas a la vez.

Adición nativa de Dart (sin contraparte en FxTS). Cuando solo necesitas el valor derivado, sigue con map; cuando lo necesitas indexado por la entrada como tabla de búsqueda, eso es indexBy.

Demo 1 · La entrada sobrevive al map

Demo 2 · Búsquedas async con respaldo

Pruébalo tú

Ejercicio: mantén cada consulta junto a sus resultados de búsqueda.

Relacionados: map — cuando la entrada puede irse · zip — emparejar dos secuencias separadas · concurrent — acota el fan-out async después de attach