Collections: Your ultimate Javascript array handler
Tags: typescript, arrays, javascript
Published: 2022-10-24 11:03:55

---
title: Collections: Your ultimate Javascript array handler
published: true
description: 
tags: typescript, arrays, javascript
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5qf849fc7fp7qm8608j0.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2022-10-24 10:21 +0000
---

## Introduction

Collections are a super powerful class that aims to manage your arrays easily and lift the heavy work from your shoulders.

## Philosophy

Working with arrays especially complex arrays can really be a pain, thus there was a need to handle working with these arrays.

Collections are `Immutable` which means the original array is never modified, instead a new array is created and returned, also any chained method generates a new array and so one.

Any collection automatically has all internal Arrays methods available to it, so you can use any of the Array methods on a collection also each method of it will return a new instance, for example `map` will return a new collection instead of array.

It can deal with `Numbers`, `Strings` `Objects` and make massive filtering and sorting a breeze, so enough talking and let's get starting.

## Installation

```bash
npm install @mongez/collection
```

Using Yarn

```bash
yarn add @mongez/collection
```

## Usage

```ts
import { collect } from "@mongez/collection";

const collection = collect([1, 2, 3, 4, 5]);

const filtered = collection.filter((item) => item > 2);
```

Sounds simple right? but it's much more than that, let's see what else we can do with it.

## Working With Math And Numbers

Collections are shipped with many math utilities that will help you perform math operation quickly, let's see it in action

```ts
import { collect } from "@mongez/collection";

const collection = collect([1, 2, 3, 4, 5]);

const sum = collection.sum(); // 15
const average = collection.average(); // 3
const max = collection.max(); // 5
const min = collection.min(); // 1
const median = collection.median(); // 3
```

Pretty nice, oh there is more, let's make some math operations on the collection

```ts
import { collect } from "@mongez/collection";

const collection = collect([1, 2, 3, 4, 5]);

const multipliedNumbers = collection.multiply(2); // [2, 4, 6, 8, 10]
// or we can use `double` method to double the values directly
const doubledNumbers = collection.double(); // [2, 4, 6, 8, 10]

const dividedNumbers = collection.divide(2); // [0.5, 1, 1.5, 2, 2.5]
// or we can use `half` method to half the values directly
const halfNumbers = collection.half(); // [0.5, 1, 1.5, 2, 2.5]

const plusNumbers = collection.plus(2); // [3, 4, 5, 6, 7]
// we can also increment the values directly
const incrementedNumbers = collection.increment(); // [2, 3, 4, 5, 6]

const minusNumbers = collection.minus(2); // [-1, 0, 1, 2, 3]
// we can also decrement the values directly
const decrementedNumbers = collection.decrement(); // [0, 1, 2, 3, 4]
```

The amazing thing here is that we can do it as well if the array is an array of objects over certain key.

```ts
import { collect } from "@mongez/collection";

const collection = collect([
    { id: 1, price: 10 },
    { id: 2, price: 20 },
    { id: 3, price: 30 },
    { id: 4, price: 40 },
    { id: 5, price: 50 },
]);

const sum = collection.sum("price"); // 150
const average = collection.average("price"); // 30
const max = collection.max("price"); // 50
const min = collection.min("price"); // 10
const median = collection.median("price"); // 30
```

This can be also done with math operations

```ts
import { collect } from "@mongez/collection";

const collection = collect([
    { id: 1, price: 10 },
    { id: 2, price: 20 },
    { id: 3, price: 30 },
    { id: 4, price: 40 },
    { id: 5, price: 50 },
]);

const multipliedNumbers = collection.multiply("price", 2); // [20, 40, 60, 80, 100]
// or we can use `double` method to double the values directly
const doubledNumbers = collection.double("price"); // [20, 40, 60, 80, 100]

const dividedNumbers = collection.divide("price", 2); // [5, 10, 15, 20, 25]
// or we can use `half` method to half the values directly
const halfNumbers = collection.half("price"); // [5, 10, 15, 20, 25]

const plusNumbers = collection.plus("price", 2); // [12, 22, 32, 42, 52]
// we can also increment the values directly
const incrementedNumbers = collection.increment("price"); // [11, 21, 31, 41, 51]

const minusNumbers = collection.minus("price", 2); // [8, 18, 28, 38, 48]
// we can also decrement the values directly
const decrementedNumbers = collection.decrement("price"); // [9, 19, 29, 39, 49]
```

## Working With Strings

Collections are also shipped with many string utilities that will help you perform string operations quickly, let's see it in action

```ts
import { collect } from "@mongez/collection";

const collection = collect(["Hello", "World", "How", "Are", "You"]);

const appendedString = collection.appendString("!!!"); // ["Hello!!!", "World!!!", "How!!!", "Are!!!", "You!!!"]

const prependedString = collection.prependString("!!!"); // ["!!!Hello", "!!!World", "!!!How", "!!!Are", "!!!You"]

const replacedString = collection.replaceString("Hello", "Hi"); // ["Hi", "World", "How", "Are", "You"]
const removeString = collection.removeString("H");  // ["ello", "World", "ow", "Are", "You"]
```

## Working With Objects

Let's go deeper, and start dealing with objects.

### Plucking Objects

```ts
import { collect } from "@mongez/collection";

const collection = collect([
    { id: 1, name: "John" },
    { id: 2, name: "Doe" },
    { id: 3, name: "Jane" },
    { id: 4, name: "Doe" },
    { id: 5, name: "John" },
]);

const plucked = collection.pluck("name"); // ["John", "Doe", "Jane", "Doe", "John"]
```

We can also pluck multiple keys by passing an array of keys

```ts
import { collect } from "@mongez/collection";

const collection = collect([
    { id: 1, name: "John", age: 20 },
    { id: 2, name: "Doe", age: 30 },
    { id: 3, name: "Jane", age: 40 },
    { id: 4, name: "Doe", age: 50 },
    { id: 5, name: "John", age: 60 },
]);

const plucked = collection.pluck(["name", "age"]); // [["John", 20], ["Doe", 30], ["Jane", 40], ["Doe", 50], ["John", 60]]
```

## The Mighty `where` Method

The `where` method is the most powerful method in the collection, it allows you to filter the collection based on a list of predefined operations which will make it easier to filter the collection.

```ts
import { collect } from "@mongez/collection";

const collection = collect([
    { id: 1, name: "John", age: 20 },
    { id: 2, name: "Doe", age: 30 },
    { id: 3, name: "Jane", age: 40 },
    { id: 4, name: "Doe", age: 50 },
    { id: 5, name: "John", age: 60 },
    {id: 6, position: 'developer', salary: 1000 },
]);

const filtered = collection.where("age", ">", 30); // [{ id: 3, name: "Jane", age: 40 }, { id: 4, name: "Doe", age: 50 }, { id: 5, name: "John", age: 60 }]

const filtered = collection.where("age", "<", 30); // [{ id: 1, name: "John", age: 20 }, { id: 2, name: "Doe", age: 30 }]

const filtered = collection.where("age", ">=", 30); // [{ id: 2, name: "Doe", age: 30 }, { id: 3, name: "Jane", age: 40 }, { id: 4, name: "Doe", age: 50 }, { id: 5, name: "John", age: 60 }]

const filtered = collection.where("age", "<=", 30); // [{ id: 1, name: "John", age: 20 }, { id: 2, name: "Doe", age: 30 }]

const filtered = collection.where("age", "=", 30); // [{ id: 2, name: "Doe", age: 30 }]

// not equal operator
const filtered = collection.where("age", "!=", 30); // [{ id: 1, name: "John", age: 20 }, { id: 3, name: "Jane", age: 40 }, { id: 4, name: "Doe", age: 50 }, { id: 5, name: "John", age: 60 }]

// in operator
const filtered = collection.where("age", "in", [30, 40]); // [{ id: 2, name: "Doe", age: 30 }, { id: 3, name: "Jane", age: 40 }]

// not in operator
const filtered = collection.where("age", "not in", [30, 40]); // [{ id: 1, name: "John", age: 20 }, { id: 4, name: "Doe", age: 50 }, { id: 5, name: "John", age: 60 }]

// between operator, alias is `<>` can also be used with dates
const filtered = collection.where("age", "between", [30, 40]); // [{ id: 2, name: "Doe", age: 30 }, { id: 3, name: "Jane", age: 40 }]

// not between operator, can also be used as !<>

const filtered = collection.where("age", "not between", [30, 40]); // [{ id: 1, name: "John", age: 20 }, { id: 4, name: "Doe", age: 50 }, { id: 5, name: "John", age: 60 }]

// like operator
const filtered = collection.where("name", "like", "Do"); // [{ id: 2, name: "Doe", age: 30 }, { id: 4, name: "Doe", age: 50 }]

// not like operator
const filtered = collection.where("name", "not like", "Do"); // [{ id: 1, name: "John", age: 20 }, { id: 3, name: "Jane", age: 40 }, { id: 5, name: "John", age: 60 }]


// exists operator
const filtered = collection.where("salary", "exists"); // [{id: 6, position: 'developer', salary: 1000 }]

// not exists operator

const filtered = collection.where("salary", "not exists"); // [{ id: 1, name: "John", age: 20 }, { id: 2, name: "Doe", age: 30 }, { id: 3, name: "Jane", age: 40 }, { id: 4, name: "Doe", age: 50 }, { id: 5, name: "John", age: 60 }]

// is operator

const filtered = collection.where("salary", "is", undefined); // [{ id: 1, name: "John", age: 20 }, { id: 2, name: "Doe", age: 30 }, { id: 3, name: "Jane", age: 40 }, { id: 4, name: "Doe", age: 50 }, { id: 5, name: "John", age: 60 }]

// is not operator

const filtered = collection.where("salary", "is not", undefined); // [{id: 6, position: 'developer', salary: 1000 }]
```

You can see all operators [here in action](https://github.com/hassanzohdy/collection#where-operators), there are over `30` operators to be used!

## Single Values

There are also some good methods that handles single values.

```ts
import { collect } from "@mongez/collection";

const collection = collect([
    { id: 1, name: "John", age: 20 },
    { id: 2, name: "Doe", age: 30 },
    { id: 3, name: "Jane", age: 40 },
    { id: 4, name: "Doe", age: 50 },
    { id: 5, name: "James", age: 60 },
]);

// get first item
const first = collection.first(); // { id: 1, name: "John", age: 20 }

// get last item
const last = collection.last(); // { id: 5, name: "James", age: 60 }

// get random item
const random = collection.random(); // { id: 2, name: "Doe", age: 30 }

// get value using dot notation for specific index and key
const value = collection.get("0.name"); // "John"

// get first available value for the given key
const value = collection.value("name"); // "John"

// get last available value for the given key
const value = collection.lastValue("name"); // "James"
```

## Element Positions

In this section we will see how to change the position of elements in the collection.

### Swap

Using `swap` method will allow you swap between two indexes in the collection

```ts
const numbers = collect([1, 2, 3, 4, 5]);

numbers.swap(0, 4); // [5, 2, 3, 4, 1]
```

### Moving Elements

Using `move` method will allow you move an element from one index to another.

```ts
const numbers = collect([1, 2, 3, 4, 5]);

numbers.move(0, 4); // [2, 3, 4, 5, 1]
```

### Shuffling

The `shuffle` method will randomly shuffle the items in the collection.

```ts
const numbers = collect([1, 2, 3, 4, 5]);

numbers.shuffle(); // something like [2, 5, 1, 4, 3]
```

### Reverse

The `reverse` method will reverse the order of the collection's items.

```ts
const numbers = collect([1, 2, 3, 4, 5]);

numbers.reverse(); // [5, 4, 3, 2, 1]
```

> `flip` method is an alias to `reverse` method.

### Reordering

The `reorder` method will reorder the items in the collection using the given keys.

```ts
const numbers = collect([1, 2, 3, 4, 5, 6, 7]);

numbers.reorder({
    0: 3,
    1: 4,
    2: 5,
    3: 6,
    4: 0,
    5: 1,
    6: 2,
}); // [5, 6, 7, 1, 2, 3, 4]
```

It receives an object, the key is the old index, and its value is the new index.

## Grouping Values

Another useful feature is grouping values, you can group values by a key.

```ts
const users = collect([
    { name: "Ahmed", age: 20 },
    { name: "Mohamed", age: 25 },
    { name: "Ali", age: 30 },
    { name: "Hasan", age: 30 },
]);

users.groupBy("age"); 
// [
//     {
//     age: 20,
//     data: [{ name: "Ahmed", age: 20 }],
//     },
//     {
//     age: 25,
//     data: [{ name: "Mohamed", age: 25 }],
//     },
//     {
//     age: 30,
//     data: [
//         { name: "Ali", age: 30 },
//         { name: "Hasan", age: 30 },
//     ],
//     },
// ]
```

It basically creates a new array of objects, each object contains the key and the items that have the same value for that key will be added in `data` key for that grouped data.

### Group By Multiple Keys

You can also group the collection by multiple keys.

```ts

const studentsClasses = collect[
  {
    id: 1,
    class: "A",
    grade: 1,
  },
  {
    id: 2,
    class: "B",
    grade: 2,
  },
  {
    id: 3,
    class: "A",
    grade: 3,
  },
  {
    id: 4,
    class: "B",
    grade: 2,
  },
  {
    id: 5,
    class: "B",
    grade: 2,
  },
  {
    id: 6,
    class: "C",
    grade: 5,
  },
]);

studentsClasses.groupBy(["class", "grade"]);
// [
//     {
//     class: "A",
//     grade: 1,
//     items: [
//         {
//         id: 1,
//         class: "A",
//         grade: 1,
//         },
//     ],
//     },
//     {
//     class: "B",
//     grade: 2,
//     items: [
//         {
//         id: 2,
//         class: "B",
//         grade: 2,
//         },
//         {
//         id: 4,
//         class: "B",
//         grade: 2,
//         },
//         {
//         id: 5,
//         class: "B",
//         grade: 2,
//         },
//     ],
//     },
//     {
//     class: "A",
//     grade: 3,
//     items: [
//         {
//         id: 3,
//         class: "A",
//         grade: 3,
//         },
//     ],
//     },
//     {
//     class: "C",
//     grade: 5,
//     items: [
//         {
//         id: 6,
//         class: "C",
//         grade: 5,
//         },
//     ],
//     },
// ]
```

### Defining other key for grouped data

By default, the grouped data will be added in `data` key, but you can change that by passing the second argument to the `groupBy` method.

```ts
const users = collect([
    { name: "Ahmed", age: 20 },
    { name: "Mohamed", age: 25 },
    { name: "Ali", age: 30 },
    { name: "Hasan", age: 30 },
]);

users.groupBy("age", "students");

// [
//     {
//     age: 20,
//     students: [{ name: "Ahmed", age: 20 }],
//     },
//     {
//     age: 25,
//     students: [{ name: "Mohamed", age: 25 }],
//     },
//     {
//     age: 30,
//     students: [
//         { name: "Ali", age: 30 },
//         { name: "Hasan", age: 30 },
//     ],
//     },
// ]
```

## Sorting

There are also some good sort methods that will make it easier for you to sort arrays of objects.

> the original `sort` method of array will return a new collection of the sorted data as well.

### sortBy

The `sortBy` method sorts the collection's items by a given key.

```ts
const users = collect([
    { name: "Ahmed", age: 20 },
    { name: "Mohamed", age: 25 },
    { name: "Ali", age: 30 },
    { name: "Hasan", age: 30 },
]);

users.sortBy("age"); // [{ name: "Ahmed", age: 20 }, { name: "Mohamed", age: 25 }, { name: "Ali", age: 30 }, { name: "Hasan", age: 30 }]
```

### sortByDesc

The `sortByDesc` method sorts the collection's items by a given key in descending order.

```ts
const users = collect([
    { name: "Ahmed", age: 20 },
    { name: "Mohamed", age: 25 },
    { name: "Ali", age: 30 },
    { name: "Hasan", age: 30 },
]);

users.sortByDesc("age"); // [{ name: "Ali", age: 30 }, { name: "Hasan", age: 30 }, { name: "Mohamed", age: 25 }, { name: "Ahmed", age: 20 }]
```

### Sort By Multiple Keys

You can also sort the collection by multiple keys using `sortBy`.

```ts
const users = collect([
    { name: "Jane", age: 25 },
    { name: "Jack", age: 30 },
    { name: "Ali", age: 20 },
    { name: "Hasan", age: 20 },
    { name: "Hasan", age: 19 },
]);

users.sortBy({
    age: "asc",
    name: "asc",
}); // [{ name: "Hasan", age: 19 }, { name: "Ali", age: 20 }, { name: "Hasan", age: 20 }, { name: "Jane", age: 25 }, { name: "Jack", age: 30 }]
```

The method receives an object, the key will be the sorting key and its value is either `asc` or `desc` for ascending or descending order.

## Unique Values

Let's get some unique values from the array.

## Unique

The `unique` method will remove any duplicate values from the collection.

```ts
const numbers = collect([1, 2, 3, 4, 5, 5, 5]);

numbers.unique(); // [1, 2, 3, 4, 5]
```

We can also get the unique values of specific key.

```ts
const users = collect([
    { id: 1, name: "John" },
    { id: 2, name: "John" },
    { id: 3, name: "Jane" },
]);

users.unique("name"); // ["John", "Jane"]
```

## Unique List

The `uniqueList` method will return all unique elements for the given value, so the key will be matched against the uniqueness criteria, and the first unique value will return the entire object instead of just the value itself.

```ts
const users = collect([
    { id: 1, name: 'John' },
    { id: 2, name: 'John' },
    { id: 3, name: 'Jane' },
]);

users.uniqueList('name'); // [{ id: 1, name: 'John' }, { id: 3, name: 'Jane' }]
```

## Adding Unique Values

Unique values can be added to the array if any of these values are not listed in the array using `pushUnique` to add unique value at the end of the array, and `prependUnique` to add unique value at the beginning of the array.

```ts
const numbers = collect([1, 2, 3, 4, 5]);

numbers.pushUnique(6, 1, 4); // [1, 2, 3, 4, 5, 6]

numbers.prependUnique(0, 2, ,3); // [0, 1, 2, 3, 4, 5]
```

## Indexes

Let's play with indexes, shall we :)

```ts
const users = collect([
    { id: 1, name: "John" },
    { id: 2, name: "Jane" },
    { id: 3, name: "Ali" },
]);

// get all indexes in a collection
users.indexes(); // [0, 1, 2]

// get the value of a specific index
users.at(2); // 

// get all elements in even indexes
users.evenIndexes(); // [{ id: 1, name: "John" }, { id: 3, name: "Ali" }]

// get all elements in odd indexes
users.oddIndexes(); // [{ id: 2, name: "Jane" }]

// get all items except the given indexes
users.exceptIndexes(0, 2); // [{ id: 2, name: "Jane" }]

// get only the given indexes
users.onlyIndexes(0, 2); // [{ id: 1, name: "John" }, { id: 3, name: "Ali" }]
```

## Taking And Skipping

Let's take some items from the array.

### Taking Items

The `take` method returns a new collection with the specified number of items.

```ts
const users = collect([
    { id: 1, name: "John" },
    { id: 2, name: "Jane" },
    { id: 3, name: "Ali" },
]);

users.take(2); // [{ id: 1, name: "John" }, { id: 2, name: "Jane" }]

users.takeLast(2); // [{ id: 2, name: "Jane" }, { id: 3, name: "Ali" }]

users.takeWhile((user) => user.id < 3); // [{ id: 1, name: "John" }, { id: 2, name: "Jane" }]

users.takeUntil((user) => user.id === 2); // [{ id: 1, name: "John" }]
```

### Skipping items

The `skip` method returns a new collection with the specified number of items removed from the beginning.

```ts
const users = collect([
    { id: 1, name: "John" },
    { id: 2, name: "Jane" },
    { id: 3, name: "Ali" },
]);

users.skip(2); // [{ id: 3, name: "Ali" }]

users.skipLast(2); // [{ id: 1, name: "John" }]

users.skipWhile((user) => user.id < 3); // [{ id: 3, name: "Ali" }]

users.skipUntil((user) => user.id === 2); // [{ id: 3, name: "Ali" }]
```

## Counting

Let's count some values and items.

### Getting collection length

The `length` property will return the number of items in the collection.

```ts
const numbers = collect([1, 2, 3, 4, 5]);

numbers.length; // 5
```

### Counting values

The `countValue` method will return the number of occurrences for the given value.

```ts
const numbers = collect([1, 2, 3, 4, 5, 2]);

numbers.countValue(2); // 2
```

### Counting Value for key

The `count` method will return the number of occurrences for the given key and value.

```ts
const users = collect([
    { name: 'John', age: 20 },
    { name: 'Jane', age: 25 },
    { name: 'Jack', age: 30 },
    { name: 'Jill' },
]);

users.count('age'); // 3
```

### Counting each value for the given key

The `countBy` method will return the number of occurrences for each value of the given key.

```ts
const users = collect([
    { name: 'John', age: 20 },
    { name: 'Jane', age: 25 },
    { name: 'Jack', age: 30 },
    { name: 'Jill' },
]);

users.countBy('age'); // { 20: 1, 25: 1, 30: 1 }
```

## Iterating

Collections are `iterable`, so you can loop over it using `for...of` loop.

```ts
const numbers = collect([1, 2, 3, 4, 5]);

for (const number of numbers) {
    console.log(number);
}
```

## Getting array values

To convert the collection into an array, you can use the `all` method.

```ts
const numbers = collect([1, 2, 3, 4, 5]);

numbers.all(); // [1, 2, 3, 4, 5]
```

> `toArray` is an alias of `all` method.

## Merge

The `merge` method will merge the given array or collection with the original collection.

```ts
const numbers = collect([1, 2, 3, 4, 5]);

const merged = numbers.merge([6, 7, 8, 9, 10]); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```

It can also merge another collection

```ts
const numbers = collect([1, 2, 3, 4, 5]);

const merged = numbers.merge(collect([6, 7, 8, 9, 10])); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```

> `concat` is an alias of `merge` method.

## Collecting all data from certain key

The `collectFrom` method will allow you to collect items from a given key of each element.

```ts
const users = collect([
    { name: 'John', age: 20, pets: ['dog', 'cat'] },
    { name: 'Jane', age: 25, pets: ['dog', 'cat'] },
    { name: 'Jack', age: 30, pets: ['dog', 'cat'] },
    { name: 'Jill', age: 35, pets: ['dog', 'cat'] },
]);

users.collectFrom('pets'); // ['dog', 'cat', 'dog', 'cat', 'dog', 'cat', 'dog', 'cat']
```

## Collecting from certain key only

The `collectFromKey` method allow you to create a new collection from the given key directly, the key supports dot notation, starting with the index.

```ts
const users = collect([
    { name: 'John', age: 20, pets: ['dog', 'cat'] },
    { name: 'Jane', age: 25, pets: ['dog', 'cat'] },
    { name: 'Jack', age: 30, pets: ['dog', 'cat'] },
    { name: 'Jill', age: 35, pets: ['dog', 'cat'] },
]);

users.collectFromKey('0.pets'); // ['dog', 'cat']
```

## Collecting from iterators

The `collect` function can be used to convert an iterable into a collection using `collect.fromIterator` method.

```ts
const numbers = collect.fromIterator([1, 2, 3, 4, 5].values());
```

## Create empty collection

The `collect` function can also be used to create an empty collection using `collect.create(length: number, initialValue: any)` method.

```ts
const numbers = collect.create(10); // [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]
```

You can also specify the initial value.

```ts
const numbers = collect.create(10, 0); // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
```

Also specify initial value based on index.

```ts
const numbers = collect.create(10, (index) => index); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
```

## Conclusion

At the end, i hope you enjoyed the article, and i hope you will find it useful.

Collection is a very useful tool, and i hope you will use it in your projects.

The article doesn't cover all the methods, you can read the entire documentation of it in the [Repository Page](https://github.com/hassanzohdy/collection).

Feel free to give me a comment and feedback, and if you have any questions, feel free to ask.

Thanks for reading.