# Reducer

A class representing a generic reducer for aggregating array elements using a selector and/or a comparator. Aggregation process can involve summing numeric values, finding minimum or maximum elements, performing folds or scans, or applying custom reduction functions.

```typescript
const result = [3, 1, 4, 1, 5, 9, 2]
    .reducer()
    .sumOf(item => item);
console.log(result); 
// Output: 25
```

## Global Functions

### reducerOf

Creates a new instance of the Reducer class from an array of items.

```typescript
const numbers = [3, 1, 4, 1, 5, 9, 2];
const numberReducer = reducerOf(numbers);
console.log(numberReducer.sumOf(item => item)); 
// Output: 25
```

## Static Functions

### of

Creates a new Reducer instance from an array of items and a comparator function.

```typescript
const numberReducer = Reducer.of([3, 1, 4, 1, 5, 9, 2]);
```

## Class Functions

### sumOf

Sums the values by applying a selector function to each element in the array.

```typescript
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reducer().sumOf((num) => num);
console.log(sum); 
// Output: 15
```

### min

Finds the minimum element in an array by using a comparator function to determine the order of the elements.

```typescript
const numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5];
const minResult = numbers.reducer().min((a, b) => a - b);
console.log(minResult); 
// Output: 1
```

### max

Finds the maximum element in an array by using a comparator function to determine the order of the elements.

```typescript
const numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5];
const maxResult = numbers.reducer().max((a, b) => a - b);
console.log(maxResult); 
// Output: 9
```

### maxBy

Finds the maximum element in an array by comparing the results of a given selector function.

```typescript
const people = [
  { name: 'Alice', age: 30 },
  { name: 'Bob', age: 25 },
  { name: 'Charlie', age: 35 }
];
const maxByAge = people.reducer().maxBy((person) => person.age);
console.log(maxByAge); 
// Output: { name: 'Charlie', age: 35 }
```

### minBy

Finds the minimum element in an array by comparing the results of a given selector function.

```typescript
const people = [
  { name: 'Alice', age: 30 },
  { name: 'Bob', age: 25 },
  { name: 'Charlie', age: 35 }
];
const minByAge = people.reducer().minBy((person) => person.age);
console.log(minByAge); 
// Output: { name: 'Bob', age: 25 }
```

### minOf

Finds the minimum element in an array by applying a selector function to each element and comparing the results.

```typescript
const people = [
  { name: 'Alice', age: 30 },
  { name: 'Bob', age: 25 },
  { name: 'Charlie', age: 35 }
];
const minOfAge = people.reducer().minOf((person) => person.age);
console.log(minOfAge); 
// Output: { name: 'Bob', age: 25 }
```

### maxOf

Finds the maximum element in an array by applying a selector function to each element and comparing the results.

```typescript
const people = [
  { name: 'Alice', age: 30 },
  { name: 'Bob', age: 25 },
  { name: 'Charlie', age: 35 }
];
const maxOfAge = people.reducer().maxOf((person) => person.age);
console.log(maxOfAge); 
// Output: { name: 'Charlie', age: 35 }
```

### minOfWith

Finds the minimum element in an array by applying a custom comparator function to the results of a selector function.

```typescript
const people = [
  { name: 'Alice', age: 30 },
  { name: 'Bob', age: 25 },
  { name: 'Charlie', age: 35 }
];
const minOfAge = people.reducer().minOfWith((person) => person.age, (a, b) => a - b);
console.log(minOfAge); 
// Output: { name: 'Bob', age: 25 }
```

### maxOfWith

Finds the maximum element in an array by applying a custom comparator function to the results of a selector function.

```typescript
const people = [
  { name: 'Alice', age: 30 },
  { name: 'Bob', age: 25 },
  { name: 'Charlie', age: 35 }
];
const maxOfAge = people.reducer().maxOfWith((person) => person.age, (a, b) => a - b);
console.log(maxOfAge); 
// Output: { name: 'Charlie', age: 35 }
```

### fold

Folds the elements of the array to a single value by applying a folder function. Similar to reduce, but the folder function is curried.

```typescript
const numbers = [1, 2, 3, 4, 5];
const product = numbers.reducer().fold((num) => (acc) => acc * num, 1);
console.log(product); 
// Output: 120
```

### foldRight

Folds the elements of the array from right to left to a single value by applying a folder function.

```typescript
const numbers = [1, 2, 3, 4, 5];
const result = numbers.reducer().foldRight((num) => (acc) => acc - num, 0);
console.log(result); 
// Output: -5 (0 - 1 - 2 - 3 - 4 - 5)
```

### reduceIndexed

Reduces the elements of an array to a single value by applying a reducer function that takes an accumulator, the current element, and the current index. It allows for index-based operations during the reduction process.

```typescript
const numbers = [1, 2, 3, 4, 5];
const product = numbers.reducer().reduceIndexed((acc, num, index) => acc * (num + index), 1);
console.log(product); 
// Output: 120 (1 * (1 + 0) * (2 + 1) * (3 + 2) * (4 + 3) * (5 + 4))
```

### foldIndexed

Folds the elements of an array into a single value by applying a curried folder function with index information.

```typescript
const numbers = [1, 2, 3, 4, 5];
const product = numbers.reducer().foldIndexed((num, index) => (acc) => acc * (num + index), 1);
console.log(product); 
// Output: 120 (1 * (1 + 0) * (2 + 1) * (3 + 2) * (4 + 3) * (5 + 4))
```

### reduce

Reduces the items in the array to a single value using the specified reducer function.

```typescript
const numbers = [3, 1, 4, 1, 5, 9, 2];
const numberReducer = Reducer.of(numbers);

const sum = numberReducer.reduce((acc, num) => acc + num);
// sum = 25

const product = numberReducer.reduce((acc, num) => acc * num, 1);
// product = 1080
```

### reduceRightIndexed

Reduces the elements of the array from right to left to a single value by applying a reducer function with index information.

```typescript
const numbers = [1, 2, 3, 4, 5];
const reducer = (acc, num, index) => acc - (num + index);
const result = numbers.reducer().reduceRightIndexed(reducer);
console.log(result); 
// Output: -9
```

> In this example, we have an array of numbers \[1, 2, 3, 4, 5]. The reducer function subtracts each number from the accumulator, where the accumulator is initially set to the last element of the array. The index of each element is also subtracted from the accumulator. The result is -9, which is obtained by performing the following calculations: 5 - (4 + 3) - (3 + 2) - (2 + 1) - (1 + 0).

### foldRightIndexed

Folds the elements of the array from right to left to a single value by applying a folder function with index information.

```typescript
const numbers = [1, 2, 3, 4, 5];
const result = numbers.reducer().foldRightIndexed((num, index) => (acc) => acc - (num + index), 0);
console.log(result); 
// Output: -9 (0 - (5 + 4) - (4 + 3) - (3 + 2) - (2 + 1) - (1 + 0))
```

### runningFold

Performs a running fold (scan) on the elements of the array from left to right.

```typescript
const numbers = [1, 2, 3, 4, 5];
const result = numbers.reducer().runningFold((num) => (acc) => acc + num);
console.log(result); 
// Output: [0, 1, 3, 6, 10, 15] (0, 0 + 1, (0 + 1) + 2, ((0 + 1) + 2) + 3, (((0 + 1) + 2) + 3) + 4, ((((0 + 1) + 2) + 3) + 4) + 5)
```

### runningReduce

Performs a running reduce on the elements of the array from left to right.

```typescript
const numbers = [1, 2, 3, 4, 5];
const result = numbers.reducer().runningReduce((acc, num) => acc + num);
console.log(result); 
// Output: [1, 3, 6, 10, 15] (1, 1 + 2, (1 + 2) + 3, ((1 + 2) + 3) + 4, (((1 + 2) + 3) + 4) + 5)
```

### runningFoldIndexed

Performs a running fold (scan) on the elements of the array from left to right with index information.

```typescript
const numbers = [1, 2, 3, 4, 5];
const reducer = Reducer.of(numbers);
const result = numbers.reducer().runningFoldIndexed((num, index) => (acc) => acc + (num + index), 0);
console.log(result); 
// Output: [0, 1, 4, 9, 16, 25] (0, 0 + (1 + 0), (0 + (1 + 0)) + (2 + 1), ((0 + (1 + 0)) + (2 + 1)) + (3 + 2), (((0 + (1 + 0)) + (2 + 1)) + (3 + 2)) + (4 + 3), ((((0 + (1 + 0)) + (2 + 1)) + (3 + 2)) + (4 + 3)) + (5 + 4))
```

### runningReduceIndexed

Performs a running reduce operation on the elements of an array from left to right, while also providing the index information. It takes a reducer function, which takes an accumulator, the current element, and the current index, and returns a new accumulator. The method returns an array of intermediate results from the running reduce operation.

```typescript
const numbers = [1, 2, 3, 4, 5];
const reducer = (acc, num, index) => acc + (num + index);
const result = numbers.reducer().runningReduceIndexed(reducer, 0);
console.log(result); // Output: [1, 4, 9, 16, 25] (1, 1 + (2 + 1), (1 + (2 + 1)) + (3 + 2), ((1 + (2 + 1)) + (3 + 2)) + (4 + 3), (((1 + (2 + 1)) + (3 + 2)) + (4 + 3)) + (5 + 4))
```
