Ленивые списки с преобразованиями, используя генераторы и итераторы


Я построил этот очень-базовые ленивый список (я добавлю несколько методов, как я нуждаюсь в них). Вы предоставляете ее массив, генератора или любого итератора. Он создает ленивый список, который позволяет запускать конвейер преобразований в ленивой манере, что означает, что они применяются только как вытащить значения из списка.

Вот класс:

class List {
    static range(start, end) {
        return new List(function* () {
            while (start <= end) {
                yield start++;
            }
        });
    }

    constructor(source) {
        if (typeof source == 'function') {
            this.generator = source;
        } else {
            this.generator = function* () {
                yield* source;
            };
        }
    }

    filter(predicate) {
        return new List(function* () {
            for (const item of this) {
                if (predicate(item)) {
                    yield item;
                }
            }
        }.bind(this));
    }

    map(mapper) {
        return new List(function* () {
            for (const item of this) {
                yield mapper(item);
            }
        }.bind(this));
    }

    take(size) {
        return new List(function* () {
            for (const item of this) {
                if (size--) {
                    yield item;
                } else {
                    break;
                }
            }
        }.bind(this));
    }

    *[Symbol.iterator] () {
        yield* this.generator();
    }

    toArray() {
        return [...this];
    }
}

Вот простой пример, как использовать его:

List.range(1, 10 ** 9)
    .filter(number => number % 10 == 0)
    .map(number => 'Item ' + number)
    .take(5)
    .toArray();

Пробую то же самое с регулярной массива:

Array.from({ length: 10 ** 9 }, (v, i) => i + 1)
     .filter(number => number % 10 == 0)
     .map(number => 'Item ' + number)
     .slice(0, 5);

...будете запускать из памяти до ее завершения.



Комментарии
1 ответ

Я не могу хаять код, помимо использования class из которых я не любитель.

Так что я просто представить альтернативный синтаксис, который дает немного больше капсулированные защиты. Его использование немного отличается. List инстанцируют через фабрику и замок держит генератор list. Я также заморозить каждый экземпляр списка для дальнейшей защиты государства.

Он также не придется возиться с const list = this что с вашей стороны-внимание комментарий-это немного раздражало.

const lazyList = (() => {

const range = (start, end) => List(function* () {
while(start <= end) { yield start++ }
});
function List(source) {
var list;
if (typeof source === "function") { list = source }
else { list = function* () { yield* source } }

return Object.freeze({
filter(pred){
return List(function* () {
for (const item of list()) { pred(item) ? yield item : 0 }
});
},
map(map) {
return List(function* () {
for (const item of list()) { yield map(item) }
});
},
take(count) {
return List(function* () {
for (const item of list()) {
if (count--) { yield item }
else { break }
}
});
},
toArray() { return [...list()] },
*[Symbol.iterator] () { yield* list() }
});
}
return Object.freeze({range, List});

})();

2
ответ дан 23 марта 2018 в 10:03 Источник Поделиться