Collection

The collection is an object an implementing ArrayLike and Iterableopen in new window meaning it can be iterated with for... of or generators, has a .length property, and it can be indexed by numbers collection[0]. It implements all method available on the arrayopen in new window in a compatible fashion. The collection is immutable unless the methods that are expected to mutate the collection: push, pop, unshift, shift, fill.

* Despite feature parity, the type of the collection isn't interchangeable with the array given some methods are returning a collection instead of array, for example map.

Instantiating a new collection is easy as:

import { Collection, collect } from '@upfrontjs/framework'

collect([1, 2, 3]);
// or
new Collection([1, 2, 3])

The constructor can take a single argument of an item or array of items or no argument.

WARNING

Note on extending the collection.

Given the collection is immutable it creates a new instance on method calls. If you're extending the collection, and your constructor takes a non-optional nth argument, the inherited methods will not work as it's impossible to tell what extra arguments might be needed.

Methods

first

The first method returns the first element of the collection. Optionally it takes a function to pick the first element by. If the collection is empty, it returns undefined.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.first(); // 1

collection.first(number => number > 2); // 3

last

The last method returns the last element in the collection. Optionally it takes a function to pick the last element by. If the collection is empty, it returns undefined.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.last(); // 5
collection.first(number => number < 5); // 4

random

The random method returns a random element from the collection. Optionally you may specify the number of random elements to pick. The argument's absolute value is used in case of negative integers.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.random(); // random element 
collection.random(2); // collection of 2 random elements
collection.random(collection.length); // return the whole collection

shuffle

The shuffle method returns the collection with the items in a randomised order.

import { Collection } from '@upfrontjs/framework';

const numCollection = new Collection([1, 2, 3, 4, 5]);

numCollection.shuffle(); // Collection[3, 1, 4, 2, 5]
numCollection.shuffle(); // Collection[2, 5, 1, 4, 3]

is

The is method determines if the collection is equal to the given collection. It uses deep equality to ensure every element in the collection is equal to the given collection in the same order.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.is(collection); // true
collection.is(new Collection([1, 2, 3, 4, 5])); // true
collection.is(collection.slice(0, 1)); // false
(new Collection([{ id: 1 }])).is(new Collection([{ id: 2 }])); // false

isEmpty

The isEmpty method determines whether the collection is empty or not.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.isEmpty(); // false
(new Collection).isEmpty(); // true

isNotEmpty

The isNotEmpty method determines whether the collection is not empty or is empty.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.isNotEmpty(); // true
(new Collection).isNotEmpty(); // false

hasDuplicates

The hasDuplicates method determines if there are any duplicates in the collection based on deep equality.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.hasDuplicates(); // false
(new Collection([1, 1])).hasDuplicates(); // true

unique

The unique method de-duplicates the collection based on deep equality. Optionally it takes one argument which is a string or function. On a function argument, the equality will be evaluated based on the function's return value. If the given argument is a string and all items in the collection are objects then if the object's key matching the string it will be based on the value's deep equality.

import { Collection } from '@upfrontjs/framework';

let collection = new Collection([1, 2, 1, 4, 5]);
collection.unique(); // Collection[1, 2, 4, 5]

collection = new Collection([
    { id: 1, name: 'name1' },
    { id: 2, name: 'name2' },
    { id: 3, name: 'name1' },
]);

collection.unique('name'); // Collection[{ id: 1, name: 'name1' },{ id: 2, name: 'name2' }]
collection.unique(obj => object.name); // Collection[{ id: 1, name: 'name1' },{ id: 2, name: 'name2' }]

duplicates

The duplicates method returns only the duplicates from the collection. Optionally it takes one argument which is a string or function. On a function argument, the equality will be evaluated based on the function's return value. If the given argument is a string and all items in the collection are objects then if the object's key matching the string it will be based on the value's deep equality.

import { Collection } from '@upfrontjs/framework';

let collection = new Collection([1, 2, 1, 4, 5]);
collection.duplicates(); // Collection[1]

collection = new Collection([
    { id: 1, name: 'name1' },
    { id: 2, name: 'name2' },
    { id: 3, name: 'name1' }
]);

collection.duplicates('name'); // Collection[{ id: 1, name: 'name1' }]
collection.duplicates(obj => object.name); // Collection[{ id: 1, name: 'name1' }]

delete

The delete method removes all elements that deep equal to the given value;

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.delete(3); // Collection[1, 2, 4, 5]

nth

The nth method returns only every nth item in the collection.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.nth(2); // Collection[2, 4]

withoutEmpty

The withoutEmpty method filters out every null and undefined values from the collection.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, null, 3, 4, 5, undefined]);
collection.withoutEmpty(); // Collection[1, 2, 3, 4, 5]

pad

The pad method pads the collection to the given length with the given optional value. The value if it's a function, will be called. If the given length is a negative integer the value will be prepended.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3]);
collection.pad(5); // Collection[1, 2, 3, undefined, undefined]
collection.pad(1); // Collection[1, 2, 3]
collection.pad(-5); // Collection[undefined, undefined, 1, 2, 3]
collection.pad(4, 'value'); // Collection[1, 2, 3, 'value']
collection.pad(4, () => 'return value'); // Collection[1, 2, 3, 'return value']

union

The union method joins one or more iterables without overlapping values based on deep equality.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.union(1, [4, 6], new Collection(7)); // Collection[1, 2, 3, 4, 5, 6, 7]

diff

The diff method returns the difference between the collection and the given item or array/collection based on deep equality.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.diff([2, 3, 4, 5, 6]); // Collection[1, 6]
collection.diff(1); // Collection[2, 3, 4, 5]

intersect

The intersect method returns the values that are present in both the collection, and the given value.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.intersect(1); // Colection[1]
collection.intersect(new Collection([3, 4, 5, 6])); // Colection[3, 4, 5]

chunk

The chunk method returns a collection of collections with the given size.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.chunk(2); // Collection[Collection[1, 2], Collection[3, 4], Collection[5]]
collection.chunk(5); // Collection[Collection[1, 2, 3, 4, 5]]

chunkBy

The chunkBy method returns an object where the keys are the resolved key values. The method also accepts a callback function which can be used to chunk by deeply nested key values.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([
    { id: 0, parentId: 5 },
    { id: 1, parentId: 5 },
    { id: 2, parentId: 3 },
    { id: 3, parentId: 3 },
    { id: 4, parentId: 3 }
]);

/**
 * Will result in:
 * {
 *     '5': Collection[{ id: 0, parentId: 5 },{ id: 1, parentId: 5 }],
 *     '3': Collection[{ id: 2, parentId: 3 },{ id: 3, parentId: 3 },{ id: 4, parentId: 3 }],
 * }
 */
collection.chunkBy('parentId');

/**
 * Will result in:
 * {
 *     '5': Collection[{ id: 0, parentId: 5 },{ id: 1, parentId: 5 }],
 *     '3': Collection[{ id: 2, parentId: 3 },{ id: 3, parentId: 3 },{ id: 4, parentId: 3 }],
 * }
 */
collection.chunkBy(item => item.parentKey);

when

The when method executes the given method if the first argument evaluates to true. The method has to return the collection.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.when(true, collectionCopy => collectionCopy.nth(2)); // Collection[2, 4]
collection.when(() => false, collectionCopy => collectionCopy.nth(2)); // Collection[1, 2, 3, 4, 5]

unless

The unless method executes the given method if the first argument evaluates to false. The method has to return the collection.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.unless(false, collectionCopy => collectionCopy.nth(2)); // Collection[2, 4]
collection.unless(() => true, collectionCopy => collectionCopy.nth(2)); // Collection[1, 2, 3, 4, 5]

whenEmpty

The whenEmpty method executes the given method if the collection is empty.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
let count = 0;
collection.whenEmpty(collectionCopy => count++);
count; // 0
(new Collection).whenEmpty(collectionCopy => count++);
count; // 1

whenNotEmpty

The whenNotEmpty method executes the given method when the collection is not empty.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
let count = 0;
collection.whenNotEmpty(collectionCopy => count++);
count; // 1
(new Collection).whenNotEmpty(collectionCopy => count++);
count; // 1

take

The take method returns given number of items. On negative integer, it returns items from the end first.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.take(2); // Collection[1, 2]
collection.take(-2); // Collection[4, 5]

takeUntil

The takeUntil method takes items from the collection until the given function called with the item returns false.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.takeUntil(item => item >= 4); // Collection[1, 2, 3]

takeWhile

The takeWhile method takes items from the collection until the given function called with the item returns true.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.takeWhile(item => item < 4); // Collection[1, 2, 3]

skip

The skip method skips the given number of items in the collection.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.skip(3); // Collection[4, 5]

skipUntil

The skipUntil method skips items until the given function returns false.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.skipUntil(item => item > 2); // Collection[3, 4, 5]

skipWhile

The skipWhile method skips items until the given function returns true.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.skipWhile(item => item <= 2); // Collection[3, 4, 5]

partition

The partition method separates the items into two collections based on the given callback's boolean value.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
const [
    failingPartition, // Collection([1, 2, 3]))
    pasingPartition // Collection([4, 5])
] = collection.partition(item => item > 3);

pluck

When all items in the collections are objects then you may use to The pluck method to get certain attributes in a collection or multiple attributes in a collection of objects. Similarly to dataGet You may also use dot notation.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection(
    { id: 1, name: 'name1', email: 'test1@email.com', property: { key: 'value1' } },
    { id: 2, name: 'name2', email: 'test2@email.com', property: { key: 'value2' } },
    { id: 3, name: 'name3', email: 'test3@email.com', property: { key: 'value3' } },
);
collection.pluck('name'); // Collection['name1', 'name2', 'name3']
collection.pluck(['id', 'name']); // Collection[{ id: 1, name: 'name1' }, { id: 2, name: 'name2' }, { id: 3, name: 'name3' }]

collection.pluck('property.key'); // Collection['value1', 'value2', 'value3']
collection.pluck(['property.key', 'id']); // Collection[{ id: 1, 'property.key': 'value1' }, { id: 2, 'property.key': 'value2' }, { id: 3, 'property.key': 'value3' }]

tap

The tap method executes the given function with the collection without changing the collection.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.tap(collectionCopy => collection.take(2)); // Collection([1, 2, 3, 4, 5])

pipe

The pipe method executes the given function with the collection. The function must return the collection.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.pipe(collectionCopy => collection.take(2)); // Collection([1, 2])

dump

The dump method is a debugging function which prints out the collection in its current state to the console. It is chainable. Optionally it can take a message argument.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.dump(); // logged: '10:37:05 - All items: 1,2,3,4,5'
collection.dump('test'); // logged: '10:37:05 (test) - All items: 1,2,3,4,5'
collection.dump().take(2); // Collection[1, 2]

orderBy

When all items in the collections are objects, then you may order them using the orderBy method. The method takes one or more objects describing how the collection should be ordered. The object has two properties:

  • property - the name of the property you want to order by OR a method that accepts the collection item and returns the nested value.
  • direction - possible values are asc, desc respective to whether it should be in ascending or descending order.
const elements = [
    { id: 2, nestedObj: { name: '2' } },
    { id: 1, nestedObj: { name: '5' } },
    { id: 1, nestedObj: { name: '1' } },
    { id: 4, nestedObj: { name: '4' } },
    { id: 3, nestedObj: { name: '3' } }
];

const collection = new Collection(elements);

collection.orderBy(
    { property: 'id', directions: 'asc' },
    { property: element => element.nestedObj.name, direction: 'desc' }
).at(1)!.nestedObj.name === '1'; // true

collection.orderBy(
    { property: element => element.nestedObj.name, direction: 'asc' }
).at(0)!.nestedObj.name === '1'; // true

toArray

The toArray method creates an arrayopen in new window from the collection.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.toArray(); // [1, 2, 3, 4, 5]

toJSON

The toJSON method returns the JSON representation of the collection.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.toJSON(); // '{"0":1,"1":2,"2":3,"3":4,"4":5,"length":5}'

isCollection

static

The isCollection static method is used to evaluate whether the given value is a collection.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
Collection.isCollection(collection); // true
Collection.isCollection(1); // false

times

static

The times static method is used to create a new collection consisting of the given value with the given number of times. A function may also be passed which will be called with the current iteration (iteration starting at 1).

import { Collection } from '@upfrontjs/framework';

Collection.times(3, 'value'); // Collection['value', 'value', 'value']
Collection.times(3, i => i); // Collection[1, 2, 3]

forEach

The forEach works the same way as the base forEachopen in new window, except it is chainable.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2, 3, 4, 5]);
collection.forEach(number => console.log(number)).take(2); // Collection([1, 2])

includes

The includes works the same way as the base includesopen in new window, except it evaluates based on deep equality.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([{ id: 1 }, { id: 2 }]);
collection.include({ id: 2 }); // true
collection.include(2); // false

join

The join method works the same way the base joinopen in new window, except when using a collection of object the first argument is can be a property key or getter function receiving the object.

import { Collection } from '@upfrontjs/framework';

const collection = new Collection([1, 2]);
collection.join('-'); // '1-2'

const objectCollection = new Collection([{ id: 1 }, { id: 2 }]);
objectCollection.join('id', '-'); // '1-2'
objectCollection.join(obj => obj.id + 1); // '2,3'

sum

The sum method returns the summative the collection numbers while casting strings to numbers if possible otherwise throws an error. Optionally it takes a string for the property key or getter function receiving the item to return a single value.

import { Collection } from '@upfrontjs/framework';

let collection = new Collection([1, 2]);

collection.sum(); // 3

collection = new Collection(['3', '4']);
collection.sum(); // 7

collection = new Collection([{ id: 1 }, { id: 2 }]);
collection.sum('id'); // 3
collection.sum(obj => obj.id); // 3

min

The min method returns the lowest number from the collection while casting strings to numbers if possible otherwise throws an error. Optionally it takes a string for the property key or getter function receiving the item to return a single value.

import { Collection } from '@upfrontjs/framework';

let collection = new Collection([1, 2]);

collection.min(); // 1

collection = new Collection(['3', '4']);
collection.min(); // 3

collection = new Collection([{ id: 1 }, { id: 2 }]);
collection.min('id'); // 1
collection.min(obj => obj.id); // 1

max

The max method returns the highest number from the collection while casting strings to numbers if possible otherwise throws an error. Optionally it takes a string for the property key or getter function receiving the item to return a single value.

import { Collection } from '@upfrontjs/framework';

let collection = new Collection([1, 2]);

collection.max(); // 2

collection = new Collection(['3', '4']);
collection.max(); // 4

collection = new Collection([{ id: 1 }, { id: 2 }]);
collection.max('id'); // 2
collection.max(obj => obj.id); // 2

average

The average method returns the average of the number from the collection while casting strings to numbers if possible otherwise throws an error. Optionally it takes a string for the property key or getter function receiving the item to return a single value.

import { Collection } from '@upfrontjs/framework';

let collection = new Collection([1, 2]);

collection.average(); // 1.5

collection = new Collection(['3', '4']);
collection.average(); // 3.5

collection = new Collection([{ id: 1 }, { id: 2 }]);
collection.average('id'); // 1.5
collection.average(obj => obj.id); // 1.5