Media móvil de tres lecturas

Gana FxDart

Requisito

Suaviza ocho lecturas horarias de temperatura con una media móvil de tres lecturas: para cada ventana de 3 lecturas consecutivas, imprime la ventana y su media a un decimal — seis ventanas completas, sin parciales. Los datos están en el código; las dos versiones deben imprimir las líneas que aparecen bajo Salida esperada.

Salida esperada
21.0 21.6 22.4 -> avg 21.7
21.6 22.4 23.1 -> avg 22.4
22.4 23.1 22.8 -> avg 22.8
23.1 22.8 22.2 -> avg 22.7
22.8 22.2 21.9 -> avg 22.3
22.2 21.9 21.4 -> avg 21.8

Lado a lado

RxDart

FxDart

Por qué difieren

RxDart escribe una ventana deslizante como una parametrización del loteo: bufferCount(3, 1) — búferes de tres, con un búfer nuevo empezando cada evento. Funciona, pero la codificación gotea dos veces. Tienes que saber que el segundo argumento es startBufferEvery y que 1 significa «deslizante»; y al final del stream el operador vuelca sus búferes aún abiertos, así que un parcial de bajada como [21.9, 21.4] también sale, y un where((w) => w.length == 3) tiene que montar guardia por un caso que el requisito nunca mencionó.

FxDart tiene una palabra para el concepto en sí: windowed(3) produce exactamente las ventanas completas, y partial: true es la aceptación explícita de la bajada — el valor por defecto coincide con lo que una media móvil significa. Añade average como función de la biblioteca (RxDart no tiene helpers de agregación, así que la media es un reduce-y-divide hecho a mano) y el lado pull declara el requisito mientras el lado push lo codifica. Ese hueco es de vocabulario, no de modelo — pero el vocabulario existe porque las ventanas sobre un iterable son una idea nativa del pull, y este se lo lleva FxDart.

Benchmark

Apple M1 Max, 32 GB de RAM · Dart 3.12.2 (compilado AOT) · 2026-08-18

N = 100

Tiempo Empate

RxDart 103 µs
FxDart 63 µs

Memoria pico Empate

RxDart 16.7 MB
FxDart 16.5 MB

N = 1,000,000

Tiempo Gana FxDart

RxDart 1068.2 ms
FxDart 657.2 ms

Memoria pico Empate

RxDart 154.0 MB
FxDart 150.1 MB

Las barras son medianas de iteraciones cronometradas repetidas en procesos nuevos por lado (los N pequeños se agrupan por resolución del temporizador). Dos lados a menos del 5% entre sí — o a menos de 0.6 ms, una diferencia que nadie puede percibir — cuentan como empate; las carreras relativas ajustadas se vuelven a medir hasta 5 veces. En una app, cualquier cosa por debajo de unos pocos milisegundos es invisible para el usuario, gane la barra que gane. La memoria es el RSS pico del proceso. La VM de Dart y el dataset son idénticos en ambos lados, así que la diferencia entre las dos barras es lo que retiene el pipeline en sí.