I needed something similar that would deep flatten objects recursively into a string, but with customizations on different provided matchers. Based on some examples here this is what I finally ended up with, using lodash and some lodash fp functions. This way you can reduce true down to just "T" and undefined down to just "U". The matchers will need a matching key with the process. Everything else is just processed with String(item)
import _ from "lodash"
import flow from "lodash/fp/flow"
import some from "lodash/fp/some"
import reduce from "lodash/fp/reduce"
....
const deepValuesToComparableString = items => {
let matchers = {
u: _.isUndefined, n: _.isNull,
b: _.isBoolean, o: _.isObject,
a: _.isArray, z: _.stubTrue
}
let process = {
u: _.constant("U"), n: _.constant("N"),
b: b => b ? "T" : "F", o: flow(_.flatMapDeep, _.values),
a: _.flattenDeep, z: String
}
let convertForMatch = _.cond(_.zip(_.values(matchers), _.values(process)))
let stillHasDepth = some(matchers.o || matchers.a)
let valuesFor = reduce((acc, item) => [...acc, ...convertForMatch(item)], [])
let flatReduceValues = reduce((acc, item) => [
...acc, ...stillHasDepth(item)
? valuesFor(flatReduceValues(valuesFor(item)))
: valuesFor(item)
], [])
return flatReduceValues(items).join("")
}
unit test:
test("it converts a 1d array of models into a string", () => {
let someArrayData = [
new TestDataClass({ someStr: "Test1", someOtherStr: "Abc", someNum: 1, someBool: false, someObjWithArrField: { someField: "some obj field", subRows: [{someSubRowField: "123", someOtherSubRowField: "testA" }]}}),
new TestDataClass({ someStr: "Test2", someOtherStr: undefined, someNum: 2, someBool: true, someObjWithArrField: { someField: "obj field 2", subRows: [{someSubRowField: "234", someOtherSubRowField: "test B" }]}}),
new TestDataClass({ someStr: "Sfds3", someOtherStr: "GGG", someNum: 3, someBool: null, someObjWithArrField: { someField: "some field 3", subRows: [{someSubRowField: "456", someOtherSubRowField: "test C" }]}}),
]
let result = deepValuesToComparableString(someArrayData)
let expectedStr = "Test1Abc1Fsome obj field123testATest2U2Tobj field 2234test BSfds3GGG3Nsome field 3456test C"
expect(result).toEqual(expectedStr)
})