Механизм фильтров Collection

от автора

Эта статья является продолжением "Итерируем всё вместе с Collection" и здесь я расскажу о встроенном механизме Collection — фильтрах.

Итеративные методы Collection могут принимать множество различных параметров, но один из самых интересных является filter, давайте рассмотрим на примере:

// Простой map $C([1, 2, 3, 4, 5]).map(function (el) { return el * 2; }) // [2, 4, 6, 8, 10]  // А теперь только для тех элементов, которые больше 2 $C([1, 2, 3, 4, 5]).map(function (el) { return el * 2; }, {filter: function (el) { return el > 2; }}) // [6, 8, 10] 

Т.е. на любой итеративный метод, будь то map, reduce, length и т.д. можно наложить дополнительную функцию фильтр, которая будет отсеивать «лишние» элементы.

Ещё примеры:

// Количество элементов в объекте, значение которых больше 2 $C({a: 1, b: 2, c: 3, e: 4}).length(function (el) { return el > 2; }) // 2  // Количество вхождений каждого символа строки, кроме "o" $C('foo Bar').group(fuction (el) { return el; }, {filter: function (el) { return el !== 'o'; }}) 

Но это ещё не всё, Collection позволяет заранее продекларировать все необходимые фильтры, а затем вызывать их по ИД и даже комбинировать. Давайте напишем 2 фильтра: первый будет находить уникальные или не уникальные элементы в исходной коллекции, а второй «склеивать» дубликаты (сразу скажу, что я не преследую здесь цель написать наиболее оптимальный алгоритм, а просто как пример).

// Декларируем наши фильтры с помощью метода addFilter  $C().addFilter('unique', function (el, key, data, i, length) {     // Параметр this.$ содержит ссылку на пустой объект,     // который создаётся в рамках каждого итератора для использования в мемоизации (т.е. сохранение промежуточных значений)          // this.$.ready не определён, значит идёт первых проход итератора     if (!this.$.ready) {         let cache = this.$.cache = this.$.cache || new Set();         let final = this.$.final = this.$.final || new Set();          if (cache.has(el)) {             final.delete(el);                  } else {             final.add(el);             cache.add(el);         }          // Параметр this._ содержит ссылку объект,         // который содержит характеристики текущей операции (тип данных, различные ограничители и т.д.)          // Если идёт последняя итерация, то сбрасываем операцию и начинаем проход заново         if (i === (this._.endIndex || (length() - 1))) {             this.reset();             this.$.ready = true;         }          // this.FALSE специальная константа, которая означает,          // что фильтр всегда должен возвращать false, даже если его инвертировали         return this.FALSE;     }          // Идёт второй проход и у нас уже есть индексирующий объект     return this.$.final.has(el); }); 

Теперь давайте попробуем в действии

// Метод get возвращает массив элементов коллекции, которые подходят под фильтр $C([1, 2, 2, 3]).get('unique') // [1, 3]  // Только не уникальные $C([1, 2, 2, 3]).get('!unique') // [2, 2] 

А теперь напишем фильтр, который будет «склеивать» одинаковые элементы в один

$C().addFilter('merge', function (el) {     this.$.tmp = this.$.tmp || new Set();      if (!this.$.tmp.has(el)) {         this.$.tmp.add(el);          // this.TRUE антоним this.FALSE         return this.TRUE;     }      return this.FALSE; }); 

И сейчас можно запустить их вместе

// Только не уникальные $C([1, 2, 2, 3, 5, 5]).get('!unique && merge') // [2, 5] 

Следует заметить, что в составных фильтрах можно также использовать «или» || и круглые скобки для группировок, на которые также можно накладывать знак инверсии !.

Допускается создавать фильтры, которые ссылаются на другие

$C().addFilter('mix', '!unique && merge'); 

Ну и напоследок: можно назначать «активные» фильтры, которые буду использовать по умолчанию всегда, а фильтры которые буду указаны явно, будут их просто дополнять.

$C([1, 2, 2, 3, 5, 5]).setFilter('unique').get() // [1, 3] $C([1, 2, 2, 3, 5, 5]).setFilter('!unique').get('merge') // [2, 5] 

Давайте напишем условие для пагинации, скажем загрузка 2-й страницы, где на одной странице не более 10 элементов.

// Исходной коллекцией пускай будет некоторый Map $C(new Map(...)).get({     filter: '!unique && merge',     from: 10,     count: 10 }) 

Надеюсь, что эта коротенькая заметка была интересной и понятной, всем удачи!

ссылка на оригинал статьи http://habrahabr.ru/post/225995/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *