Estoy tratando de crear un generador que produzca valores entre un rango dado. Mis requisitos son:
Decidí modelar esto como un árbol, y hacer algo como una búsqueda en amplitud para dividir el rango en subdivisiones de tamaño uniforme, e iterar sobre cada capa en un orden que evita la visita de nodejs adyacentes.
Se me ocurrió la siguiente solución que funciona, sin embargo, no me gusta que esté usando recursividad, y sospecho que se puede reescribir para eliminar la recursividad (¿quizás una cola?) Un poco atascado aquí. Esto es lo que tengo hasta ahora:
function* orderedSubdivisor(start: number, end: number): Generator<number> {
const mid = (end - start) / 2 + start
yield mid
const left = orderedSubdivisor(start, mid)
const right = orderedSubdivisor(mid, end)
while (true) {
yield left.next().value
yield right.next().value
}
}
const iter = orderedSubdivisor(0, 64)
console.log(Array.from({length: 63}, () => iter.next().value))
¡Gracias!
Puede modelar esto usando un contador binario para representar la posición/ruta en su árbol. El bit menos significativo decide si se encuentra en la mitad izquierda o derecha de la rama superior, el segundo bit menos significativo decide si se encuentra en la mitad izquierda o derecha del segundo nivel, y así sucesivamente:
function* orderedSubdivisor(start, end) {
for (let i=1; true; i++) {
let sum = start;
let part = end-start;
for (let j=i; j; j=j>>>1) {
part /= 2;
if (j & 1) sum += part;
}
yield sum;
}
}
const iter = orderedSubdivisor(0, 64)
console.log(Array.from({length: 63}, () => iter.next().value))
De hecho, puede ver que esencialmente acaba de crear un contador, pero cambia el orden de bits de cada valor obtenido:
function* orderedSubdivisor(start, end) {
const mid = (end - start) / 2 + start
yield mid
const left = orderedSubdivisor(start, mid)
const right = orderedSubdivisor(mid, end)
while (true) {
yield left.next().value
yield right.next().value
}
}
let i=0;
for (const v of orderedSubdivisor(0, 64)) {
if (i++ >= 63) break;
document.body.appendChild(document.createElement('pre')).textContent = v.toString(10).padStart(2)+': 0b'+v.toString(2).padStart(6, '0');
}
Estoy tratando de crear un generador que produzca valores entre un rango dado. Mi requisito [es] tener cada valor lejos de los valores emitidos previamente.
Mi caso de uso real es la asignación de tonos en una rueda de colores.
Para eso, recomiendo la técnica de hashing de Fibonacci con la proporción áurea / ángulo áureo , que proporciona una salida distribuida muy uniformemente alrededor de la rueda de color:
function* orderedSubdivisor(start, end) {
for (let i=0; true; i+=0.6180339887498951) {
yield start+(i%1)*(end-start);
}
}
let i=0;
for (const v of orderedSubdivisor(0, 360)) {
if (i++ >= 100) break;
const p = document.body.appendChild(document.createElement('p'));
p.textContent = v;
p.style = `background-color: hsl(${v}deg, 100%, 50%)`;
}