1.8.0 • Published 1 year ago

iterate_library v1.8.0

Weekly downloads
-
License
Unlicense
Repository
github
Last release
1 year ago

iterate_library

Библиотека, реализующая методы итератора.

Мотивация

Если вам нужны методы для работы с коллекциями, то хорошо бы иметь общий интерфейс для работы с ним вне зависимосто от типа объекта. Такой интерфейс появился в ES6, в виде итераторов. Данная библиотека добавляет в ваш объект методы для рботы с коллекцией через метод [Symbol.iterator](). Следовательно она будет работать только с объектами, у которых есть этот метод. Если вы реализуете дерево, стек, очередь и т д, не нужно писать методы для его обхода, фильтрации и других методов, существующих в данной библиотеке! Просто реализуйте в вашем объекте метод [Symbol.iterator](), подключите эту библиотеку и добавьте методы для работы с вашей коллекцией.

На самом деле общий интерфейс существовал и до ES6 - это массивы. Вы можете с тем же успехом реализовать метод, который будет преобразовывать вашу коллекцию в массив, а затем использовать методы массива. Преобразованние к массиву будет происходить за время O(n), после чего вы сможете использовать сетоды массивов для обработки коллекции. Итератор же выдает по 1 элементу из коллекции, с которым работают методы библиотеки сразу же. Это позволяет избавиться от лишнего прохода по коллекции для работы с ней, как в случае с массивами. Можно назвать эту величину "Вемя доступа к коллекции", в случае с итератором она будет O(1), в отличие от O(n) в случае преобразования в массив. Более того можете взглянуть на этот код:

const array = addIterableMethodsInArray([
  {
    rating: 1,
    numbers: [1, 11, 111],
  },
  {
    rating: 2,
    numbers: [2, 22, 222],
  },
  {
    rating: 3,
    numbers: [3, 33, 333],
  },
  {
    rating: 4,
    numbers: [4, 44, 444],
  },
  {
    rating: 5,
    numbers: [5, 55, 555],
  },
]);

const result = array
  .enumerableFilter(x => {
    console.log(x.rating);
    return x.rating > 3;
  })
  .enumerableSome(x => {
    console.log(x.rating);
    return x.rating > 2;
  });

const resultNative = array
  .filter(x => {
    console.log(x.rating);
    return x.rating > 3;
  })
  .some(x => {
    console.log(x.rating);
    return x.rating > 2;
  });

В случае с итерируемой версией вы увидите 3 вывода на консоль в методе enumerableFilter() против 5 на стандартном методе массива filter(). так происходит потому, что итератор не фильтрует всю коллекцию сразу, он отдает первый элемент, который отвечает заданному условию (x.rating > 3) после чего с ним рботает следующий метод. Это хороший варинт для высоконагруженных решений!

Однако мы предостерегаем вас от преждевременной оптимизации! Не стоит использовать библиотеку просто пот тому, что она производительнее другого решения! Если у вас нет проблем с производительностью. преобразуйте к стандартному массиву и работайте с ним, что бы избежать лишних зависимостей в проекте и повышения порога входа в него. Можно скзать, что бибилиотека подходит для узкого круга задач, для нагруженных решений.

API

Все методы, которые совпадают с названиями стандртных работают примерно так же. Например метод с названием enumerableMap() соответсвуют методу map() в стандартной библиотеке. Почти все методы, которые принимают функцию обратного вызова, передают в нее последним параметром количество итераций. Массив, естественно не передается, как в обычных методах массивов, т к методы работают с итератором, а не массивом.

Список методов:

enumerableSome()

enumerableSomeStrict()

enumerableEvery()

enumerableCount()

enumerableReduce()

enumerableReduceStrict()

enumerableGroupToArray()

enumerableGroupToMap()

enumerableEveryStrict()

enumerableToArray()

enumerableToSet()

enumerableToMap()

enumerableForEach()

enumerableFirst()

enumerableFirstFluent()

enumerableFind()

enumerableFindStrict()

enumerableForEachLazy()

enumerableFilter()

enumerableMap()

enumerableFilterStrict()

enumerableFlatMap()

enumerableMergeSort()

enumerableSkip()

enumerableTake()

enumerableConcat()

Перед использованием скачайте и подключите библиотеку:

npm i iterate_library

Начиная с версии 1.8.0 можно использовать префикс, который передается вторым параметром для встроеных методов библиотеки addIterableMethodsInArray() addIterableMethodsInObject() setMethodsAllPrototypes(). Префикс по-умолчанию - "enumerable" Более того, если вы используете TS, то компилятор будет подсказывать вам о ваших методах уже с префиксами:

import { addIterableMethodsInArray } from "iterate_library";

const result = addIterableMethodsInArray([1, 2, 3, 4, 5], "myPrefix").myPrefixMap(x => x + 2);
// result:
[3, 4, 5, 6, 7]

Tooltip_all_methods

Tooltip

Для использования с прототипами перечислимых типов используйте:

import { setMethodsAllPrototypes, ILibraryMethods, addPrefixToObject } from 'iterate_library';

const myPrefixPrefix = "myPrefix";

declare global {
  interface Array<T> extends addPrefixToObject<ILibraryMethods<T, {}, typeof myPrefixPrefix>, typeof myPrefixPrefix> { }
  interface Map<K, V> extends addPrefixToObject<ILibraryMethods<[K, V], {}, typeof myPrefixPrefix>, typeof myPrefixPrefix> { }
  interface Set<T> extends addPrefixToObject<ILibraryMethods<T, {}, typeof myPrefixPrefix>, typeof myPrefixPrefix> { }
}

setMethodsAllPrototypes([
    Array,
    Map,
    Set,
  ],
    "myPrefix");

  const result = [1, 2, 3, 4, 5].myPrefixMap(x => x + 2).myPrefixToArray();
  // result:
  [3, 4, 5, 6, 7]

  const resultMap = new Map([
    [1, { name: "One" }],
    [2, { name: "Two" }],
    [3, { name: "Three" }],
  ])
    .myPrefixMap(x => x[1].name)
    .myPrefixToArray();
  // resultMap: 
  [ "One", "Two", "Three" ];


  const resultSet = new Set([1, 2, 3, 4, 5, 1, 3, 5])
    .myPrefixMap(x => x + 2)
    .myPrefixToArray();
  // resultSet: 
  [1, 2, 3, 4, 5]

Использование с конкретным объектом:

import { addIterableMethodsInArray, addIterableMethodsInObject } from "iterate_library";

const array = addIterableMethodsInArray([
  {
    rating: 1,
    numbers: [1, 11, 111],
  },
  {
    rating: 2,
    numbers: [2, 22, 222],
  },
  {
    rating: 3,
    numbers: [3, 33, 333],
  },
  {
    rating: 4,
    numbers: [4, 44, 444],
  },
  {
    rating: 5,
    numbers: [5, 55, 555],
  },
]);

addIterableMethodsInArray и addIterableMethodsInObject на самом деле внутри вызывают одину и ту же функцию. Если вы пишете на JS, то можете вызывать любую для объекта или массива. Они сделанны отдельно только для потому, что вывод системы типов в ts плохо работает для обобщенной addIterableMethodsInObject и если использовать ее, то вам придется либо работать с типом unknown либо явно передавать параметры типа:

const arr = addIterableMethodsInObject<string[], string>();

,что не очень удобно. Функция addIterableMethodsInArray лишена этой проблемы, но может работать только с массивами с точки зрения TS. Оба этих метода добавляют в существующий объект методы, не создавая новый, т к создать новый массив будет занимать время O(n), что невилирует актуальность бибилотеки.

enumerableMap()

const result = array
    .enumerableMap(x => x.rating)
    .enumerableToArray(); // [1, 2, 3, 4, 5]

const resultNative = array
    .map(x => x.rating); // [1, 2, 3, 4, 5]

enumerableFilter()

const result = array
    .enumerableFilter(x => x.rating > 3)
    .enumerableToArray(); 

// result:
[
  {
    rating: 4,
    numbers: [4, 44, 444],
  },
  {
    rating: 5,
    numbers: [5, 55, 555],
  },
]

// Native equivalent
const resultNative = array.filter(x => x.rating > 3);

enumerableFilterStrict()

Эквивалентна работе enumerableFilter() за исключением того, что внутри проверка происходит не на истинность значения, а на истинность булева значения:

if (callback(item) === true)

В обычной же enumerableFilter(), как и в filter() проверка происходит так:

if (callback(item))

Более того, функция принимает в качестве функции обратного вызова только ту, которая возвращает булево значение, о чем вам подскажет компилятор. Однако, если вы пишете программы на JS можно подставить любую фнкцию и вы получите неправильный результат, если функция обратного вызова не будет отправлять строго булево значение.

const result = array
    .enumerableFilterStrict(x => x.rating > 3)
    .enumerableToArray();

enumerableSome()

const result = array.enumerableSome(x => x.rating > 3); // true
const resultNative = array.some(x => x.rating > 3) // true

enumerableSomeStrict()

Отличается от enumerableSome() тем же, чем и enumerableFilter() от enumerableFilterStrict()

const result = array.enumerableSomeStrict(x => x.rating > 3); // true
const resultNative = array.some(x => x.rating > 3); // true

enumerableEvery()

const result = array.enumerableEvery(x => x.rating > 3); // false
const resultNative = array.every(x => x.rating > 3) // false

enumerableEveryStrict()

Отличается от enumerableEvery() тем же, чем и enumerableFilter() от enumerableFilterStrict()

const result = array.enumerableEveryStrict(x => x.rating > 3); // false
const resultNative = array.filter(x => x.rating > 3); // false

enumerableToArray()

Преобразует последовательность в массив. Применяется, когда вам нужно после всех операций с последовательностью получить результат в виде конечного значения. Например после enumerableFilter() или enumerableMap().(#enumerableMap).

const result = array.enumerableToArray(); // [...]

enumerableToMap()

Преобразует последовательность в Map(). В остальном анологичен enumerableToArray().

const result = [...array.enumerableToMap()];
// result:
[
  [1, { rating: 5,numbers: [5, 55, 555] }],
  [0, { rating: 4, numbers: [4, 44, 444 ] }],
]

enumerableToSet()

Преобразует последовательность в Set(). В остальном анологичен enumerableToArray().

const result = [...array.enumerableToSet()]; // result: array

enumerableGroupToArray()

Группирует последовательность по признаку и преобразует в массив кортежей, где первое значение будет признаком группировки, а второе - массивом всех значений, соответствующих этому признаку:

const inventory = addIterableMethodsInArray([
    { name: "asparagus", type: "vegetables", quantity: 9 },
    { name: "bananas", type: "fruit", quantity: 5 },
    { name: "goat", type: "meat", quantity: 9 },
    { name: "cherries", type: "fruit", quantity: 5 },
    { name: "fish", type: "meat", quantity: 22 },
  ]);

const group = inventory.enumerableGroupToArray(({ quantity }) => quantity);

// group: 
[
  [9, [
    { name: "asparagus", type: "vegetables", quantity: 9 },
    { name: "goat", type: "meat", quantity: 9 },
  ],
  ],
  [5, [
    { name: "bananas", type: "fruit", quantity: 5 },
    { name: "cherries", type: "fruit", quantity: 5 },
  ],
  ],
  [22, [
    { name: "fish", type: "meat", quantity: 22 },
  ],
  ],
]

enumerableGroupToMap()

Аналогичен enumerableGroupToArray(), за исключением того, что преобразует в Map()

const inventory = addIterableMethodsInArray([
    { name: "asparagus", type: "vegetables", quantity: 9 },
    { name: "bananas", type: "fruit", quantity: 5 },
    { name: "goat", type: "meat", quantity: 9 },
    { name: "cherries", type: "fruit", quantity: 5 },
    { name: "fish", type: "meat", quantity: 22 },
  ]);

const group = [...inventory.enumerableGroupToMap(({ quantity }) => quantity)];

// group: 
[
  [9, [
    { name: "asparagus", type: "vegetables", quantity: 9 },
    { name: "goat", type: "meat", quantity: 9 },
  ],
  ],
  [5, [
    { name: "bananas", type: "fruit", quantity: 5 },
    { name: "cherries", type: "fruit", quantity: 5 },
  ],
  ],
  [22, [
    { name: "fish", type: "meat", quantity: 22 },
  ],
  ],
]

enumerableForEach()

Проходит по последовательности, ничего не возвращает. Аналогичен методу массива forEach().

array.enumerableForEach(x => x.numbers = []);

// array:
[
  {
    rating: 1,
    numbers: [],
  },
  {
    rating: 2,
    numbers: [],
  },
  {
    rating: 3,
    numbers: [],
  },
  {
    rating: 4,
    numbers: [],
  },
  {
    rating: 5,
    numbers: [],
  },
];

enumerableForEachLazy()

Анологичен enumerableForEach(), но возвращает итератор, у которого есть все методы этой библиотеки. Удобно использовать, если нужно мутировать элементы последовательности и передать их дальше.

const result = array.enumerableForEachLazy(x => x.numbers = []).enumerableToArray();

enumerableFlatMap()

const result = array.enumerableFlatMap(x => x.numbers).enumerableToArray(); 
const resultNative = array.flatMap(x => x.numbers);
// result, resultNative:
[1, 11, 111, 2, 22, 222, 3, 33, 333, 4, 44, 444, 5, 55, 555]

enumerableCount()

enumerableReduce()

enumerableReduceStrict()

enumerableFirst()

enumerableFirstFluent()

enumerableFind()

enumerableFindStrict()

enumerableMergeSort()

enumerableSkip()

enumerableTake()

enumerableConcat()

1.8.0

1 year ago

1.7.0

1 year ago

1.6.1

1 year ago

1.6.0

1 year ago

1.5.0

1 year ago

1.4.4

1 year ago

1.3.4

1 year ago

1.2.4

1 year ago

1.2.3

1 year ago

1.2.2

1 year ago

1.2.1

1 year ago

1.2.0

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago