Skip to content

Commit

Permalink
Merge pull request #23 from giraugh/feat/split-array-by-util
Browse files Browse the repository at this point in the history
Add `splitArrayBy` utility
  • Loading branch information
giraugh authored May 25, 2023
2 parents dc80d3e + ced1559 commit e231394
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/fresh-elephants-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@giraugh/tools": minor
---

Add splitArrayBy utility
1 change: 1 addition & 0 deletions lib/arrays/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './zipArrays'
export * from './zipArraysLongest'
export * from './partitionArray'
export * from './rotateArray'
export * from './splitArrayBy'
60 changes: 60 additions & 0 deletions lib/arrays/splitArrayBy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* Split an array when a predicate function returns true and return all the groups
* @param arr the array to split
* @param splitFn a function over pairs of elements in the array that returns true when the elements should be in different groups
* @returns the array of groups split as per the `splitFn`
*
* @example
* const runs = splitArrayBy([1, 2, 3, 10, 11, 12], (a, b) => b - a > 1)
* runs // [[1, 2, 3], [10, 11, 12]]
*/
export const splitArrayBy = <T>(arr: T[], splitFn: (a: T, b: T) => boolean): T[][] => {
// Handle special case of empty array
if (arr.length === 0) return []

let groups: T[][] = [[]]
while (true) {
// Shift one element and peak the next element
if (arr.length === 0) break
let [x, y] = [arr.shift()!, arr.at(0)]

// Add element to current group
groups.at(-1)!.push(x)

// Start new group?
if (arr.length > 0 && splitFn(x, y!))
groups.push([])
}

return groups
}

if (import.meta.vitest) {
const { expect, it } = import.meta.vitest

it('works for example 1', () => {
const runs = splitArrayBy([1, 2, 3, 10, 11, 12], (x, y) => Math.abs(y - x) > 1)
expect(runs).toEqual([[1, 2, 3], [10, 11, 12]])
})

it('handles single group', () => {
const groups = splitArrayBy([1, 2, 3], () => false)
expect(groups).toEqual([[1, 2, 3]])
})

it('handles many splits', () => {
const groups = splitArrayBy([1, 2, 3], () => true)
expect(groups).toEqual([[1], [2], [3]])
})

it('handles special case of empty array', () => {
const groups = splitArrayBy([], () => true)
expect(groups).toEqual([])
})

it('handles falsy values', () => {
const groups = splitArrayBy([1, 1, 1, undefined, undefined, 2, 2, 2], (x, y) => !!x !== !!y)
expect(groups).toEqual([[1, 1, 1 ], [undefined, undefined], [2, 2, 2]])
})
}

0 comments on commit e231394

Please sign in to comment.