I have an object:
myObject = { \'a\': 1, \'b\': 2, \'c\': 3 }
I am looking for a native method, similar to Array.prototype.map
EDIT: The canonical way using newer JavaScript features is -
const identity = x =>
x
const omap = (f = identity, o = {}) =>
Object.fromEntries(
Object.entries(o).map(([ k, v ]) =>
[ k, f(v) ]
)
)
Where o
is some object and f
is your mapping function. Or we could say, given a function from a -> b
, and an object with values of type a
, produce an object with values of type b
. As a pseudo type signature -
// omap : (a -> b, { a }) -> { b }
The original answer was written to demonstrate a powerful combinator, mapReduce
which allows us to think of our transformation in a different way
m
, the mapping function – gives you a chance to transform the incoming element before…r
, the reducing function – this function combines the accumulator with the result of the mapped elementIntuitively, mapReduce
creates a new reducer we can plug directly into Array.prototype.reduce
. But more importantly, we can implement our object functor implementation omap
plainly by utilizing the object monoid, Object.assign
and {}
.
const identity = x =>
x
const mapReduce = (m, r) =>
(a, x) => r (a, m (x))
const omap = (f = identity, o = {}) =>
Object
.keys (o)
.reduce
( mapReduce
( k => ({ [k]: f (o[k]) })
, Object.assign
)
, {}
)
const square = x =>
x * x
const data =
{ a : 1, b : 2, c : 3 }
console .log (omap (square, data))
// { a : 1, b : 4, c : 9 }
Notice the only part of the program we actually had to write is the mapping implementation itself –
k => ({ [k]: f (o[k]) })
Which says, given a known object o
and some key k
, construct an object and whose computed property k
is the result of calling f
on the key's value, o[k]
.
We get a glimpse of mapReduce
's sequencing potential if we first abstract oreduce
// oreduce : (string * a -> string * b, b, { a }) -> { b }
const oreduce = (f = identity, r = null, o = {}) =>
Object
.keys (o)
.reduce
( mapReduce
( k => [ k, o[k] ]
, f
)
, r
)
// omap : (a -> b, {a}) -> {b}
const omap = (f = identity, o = {}) =>
oreduce
( mapReduce
( ([ k, v ]) =>
({ [k]: f (v) })
, Object.assign
)
, {}
, o
)
Everything works the same, but omap
can be defined at a higher-level now. Of course the new Object.entries
makes this look silly, but the exercise is still important to the learner.
You won't see the full potential of mapReduce
here, but I share this answer because it's interesting to see just how many places it can be applied. If you're interested in how it is derived and other ways it could be useful, please see this answer.