Skip to content

Instantly share code, notes, and snippets.

@dalcib
Forked from eenblam/gather-final.js
Last active October 15, 2019 11:05
Show Gist options
  • Save dalcib/e1d8a53e01d7098913e4dc4d656c1212 to your computer and use it in GitHub Desktop.
Save dalcib/e1d8a53e01d7098913e4dc4d656c1212 to your computer and use it in GitHub Desktop.
Naive JS implementation of tidyr's gather function. Intended for use with JSON-styled tabular data... like you'd get from d3.dsv
function withFields<S>(record: S, fields: (keyof S)[]) {
// Returns record with only properties specified in fields
return fields.reduce((acc: Partial<S>, key) => {
acc[key] = record[key]
return acc
}, {})
}
function splitRecord<S extends object>(record: S, ...fields: Array<keyof S>) {
let withGivenFields = withFields(record, fields)
let otherFields = keys(record).filter((key: keyof S) => !fields.includes(key))
let withOtherFields = withFields(record, otherFields)
return [withOtherFields, withGivenFields]
}
function keys<O extends object>(obj: O): Array<keyof O> {
return Object.keys(obj) as Array<keyof O>
}
function lengthen<S extends object>(record: Partial<S>, keyLabel: string, valueLabel: string) {
return keys(record).map(key => ({ [keyLabel]: key, [valueLabel]: record[key] }))
}
export function gather<S extends object = object>(
data: S[],
keyLabel: string,
valueLabel: string,
...columns: (keyof S)[]
) {
let result: any
return data
.map(record => {
let [keptFields, wideFields] = splitRecord(record, ...columns)
let longFields = lengthen<S>(keptFields, keyLabel, valueLabel)
let nestedArrays = longFields.map(longField => Object.assign({}, wideFields, longField))
return nestedArrays
})
.reduce((acc, arr) => acc.concat(arr), [])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment