alter
alter
(reducerFn: ReducerFn, makeInitial: MakeInitialFn) => (collection: Collection) => Result
Alter a collection into something else
Below, we have a table of goals and assists for a soccer game. Tables aren't very developer-friendly, so let's alter it to an object.
const [_headers, ...stats] = [ ['name', 'goals', 'assists'], ['phil', 1, 0], ['mary', 0, 2], ['sarah', 2, 1], ] const makeEmptyObj = () => ({}) const toStatsObj = (statsObj, statsArr) => { const [name, goals, assists] = statsArr statsObj[name] = { goals, assists } return statsObj } const makeStatsObj = alter(toStatsObj, makeEmptyObj) const statsObj = makeStatsObj(stats) console.log(statsObj) // is { // phil: { goals: 1, assists: 0 }, // mary: { goals: 0, assists: 2 }, // sarah: { goals: 2, assists: 1 } // }
type StatsArr = [string, number, number] type StatsTable = [string[], ...StatsArr[]] const table: StatsTable = [ ['name', 'goals', 'assists'], ['phil', 1, 0], ['mary', 0, 2], ['sarah', 2, 1], ] const [_headers, ...stats] = table type StatsObj = { goals: number assists: number } type StatsByPlayer = Record<string, StatsObj> const makeEmptyObj = () => ({}) as StatsByPlayer const toStatsObj = (statsObj: StatsByPlayer, statsArr: StatsArr) => { const [name, goals, assists] = statsArr statsObj[name] = { goals, assists } return statsObj } const makeStatsObj = alter(toStatsObj, makeEmptyObj)<StatsArr[]> const statsObj = makeStatsObj(stats) console.log(statsObj) // is { // phil: { goals: 1, assists: 0 }, // mary: { goals: 0, assists: 2 }, // sarah: { goals: 2, assists: 1 } // }
const [_headers, ...stats] = [ ['name', 'goals', 'assists'], ['phil', 1, 0], ['mary', 0, 2], ['sarah', 2, 1], ] const makeEmptyObj = () => ({}) const toStatsObj = (statsObj, statsArr) => { const [name, goals, assists] = statsArr statsObj[name] = { goals, assists } return statsObj } const makeStatsObj = alter( toStatsObj, makeEmptyObj ) const statsObj = makeStatsObj(stats) console.log(statsObj) // is { // phil: { goals: 1, assists: 0 }, // mary: { goals: 0, assists: 2 }, // sarah: { goals: 2, assists: 1 } // }
type StatsArr = [string, number, number] type StatsTable = [string[], ...StatsArr[]] const table: StatsTable = [ ['name', 'goals', 'assists'], ['phil', 1, 0], ['mary', 0, 2], ['sarah', 2, 1], ] const [_headers, ...stats] = table type StatsObj = { goals: number assists: number } type StatsByPlayer = Record<string, StatsObj> const makeEmptyObj = () => ({}) as StatsByPlayer const toStatsObj = ( statsObj: StatsByPlayer, statsArr: StatsArr ) => { const [name, goals, assists] = statsArr statsObj[name] = { goals, assists } return statsObj } const makeStatsObj = alter( toStatsObj, makeEmptyObj )<StatsArr[]> const statsObj = makeStatsObj(stats) console.log(statsObj) // is { // phil: { goals: 1, assists: 0 }, // mary: { goals: 0, assists: 2 }, // sarah: { goals: 2, assists: 1 } // }
See 'What' for example code.
I suggest using alter when you need to iterate over a collection to produce a result and other utilities aren't better suitors.
Confused? See 'Notes' for why this utility is difficult to explain.
This utility is similar to reduce, a function I find difficult to explain. The primary issue is its usage not matching its etymology nor our intuition of what reduce means. I believe 'alter' is much more fitting. Another issue is how the function can be used more broadly than others. For instance, you could filter or map over an array using reduce, while the opposite is not true. Because it's so broad, we can't give a focused explanation for its purpose. It'd be like explaining when to use a for loop.
With that out of the way, reduce is still a helpful tool. This is why I'm including alter in Common FP.