Use ramda `sequence` to traverse a dictionary

742 Views Asked by At

How can I use ramda's sequence to traverse a dictionary?

Given the following dictionary

cars = {color: ['yellow', 'red'], year: [2017], model: ['coup', 'sedan']}

I'd like to produce the traversed result

all_cars = [
    {color: 'yellow', year: 2017, model: 'coup'},
    {color: 'yellow', year: 2017, model: 'sedan'},
    {color: 'red', year: 2017, model: 'coup'},
    {color: 'red', year: 2017, model: 'sedan'}
]

Using R.sequence results in a list of an empty list

R.sequence(R.of, cars)
[[]]

If I traverse a list instead of a dictionary it produces the correct cartesian product, but the results are (of course) lists instead of dictionaries.

R.sequence(R.of, [['yellow', 'red'], [2017], ['coup', 'sedan']])
[["yellow", 2017, "coup"], ["yellow", 2017, "sedan"], ["red", 2017, "coup"], ["red", 2017, "sedan"]]
1

There are 1 best solutions below

6
Scott Sauyet On

I can think of two ways to do this, one involving sequence, and the other not.

This one uses your sequence(of) call above:

const convert = lift(map)(
  compose(zipObj, keys), 
  compose(sequence(of), values)
)

const all_cars = convert(cars);

The other was built by my usual technique of keep changing the output with one transformation after another until I get to what I want:

const combine = pipe(
  toPairs,
  map(apply(useWith(map, [objOf, identity]))),
  reduce(xprod, [[]]),
  map(flatten),
  map(mergeAll)
)

const all_cars = combine(cars)

This might be made a little clearer by introducing a crossproduct across multiple lists:

const xproduct = reduce(pipe(xprod, map(unnest)), [[]])

const combine = pipe(
  toPairs,
  map(apply(useWith(map, [objOf, identity]))),
  xproduct,
  map(mergeAll)
)

The second version is what I came up with on first trying the problem. Then when I looked to see what you'd tried, I got that first version. That first version looks cleaner to me, although most of the individual steps in the second one are trivial. But since there is one non-trivial step in there, the first one seems an overall winner.

You can see the first or the second on the Ramda REPL.