How to convert an array of objects into an array of arrays using Ramda

65 Views Asked by At

I would like to transform this:

[
  { a: 2000, b: 4000 },
  { a: 8000, b: 5000 },
  { a: 6000, b: 1000 }
];

Into this:

[
  [ 2000, 8000, 6000 ],
  [ 4000, 5000, 1000 ]
];

Using Ramda.

I can do this using just R.reduce, but I'm wondering if there's a way that uses as little custom code as possible and instead makes full use of the functions Ramda provides.

One more caveat; the solution can't assume that the keys in the objects are known. They will always be consistent between objects, but may change every time this function is run. For example, the next run of the code could be:

Input:

[
  { c: 1000, d: 4000, e: 7000 },
  { c: 2000, d: 5000, e: 8000 },
  { c: 3000, d: 6000, e: 9000 }
];

Result:

[
  [ 1000, 2000, 3000 ],
  [ 4000, 5000, 6000 ],
  [ 7000, 8000, 9000 ],
];

2

There are 2 best solutions below

1
Mr. Polywhirl On BEST ANSWER

Just use vanilla JS and transpose the mapped object values.

transpose(input.map(Object.values));

const transpose = (a) => a[0].map((_, i) => a.map(r => r[i]));

{
  const
    input = [
      { a: 2000, b: 4000 },
      { a: 8000, b: 5000 },
      { a: 6000, b: 1000 }
    ],
    expected = [
      [ 2000, 8000, 6000 ],
      [ 4000, 5000, 1000 ]
    ],
    actual = transpose(input.map(Object.values));

  console.log(JSON.stringify(actual) === JSON.stringify(expected));
}

{
  const
    input = [
      { c: 1000, d: 4000 },
      { c: 2000, d: 5000 },
      { c: 3000, d: 6000 }
    ],
    expected = [
      [ 1000, 2000, 3000 ],
      [ 4000, 5000, 6000 ]
    ],
    actual = transpose(input.map(Object.values));

  console.log(JSON.stringify(actual) === JSON.stringify(expected));
}

Here is the equivalent in Rambda:

R.transpose(R.map(R.values, input));             // or
R.transpose(R.compose(R.map(R.values))(input));

{
  const
    input = [
      { a: 2000, b: 4000 },
      { a: 8000, b: 5000 },
      { a: 6000, b: 1000 }
    ],
    expected = [
      [ 2000, 8000, 6000 ],
      [ 4000, 5000, 1000 ]
    ],
    actual = R.transpose(R.map(R.values, input));

  console.log(JSON.stringify(actual) === JSON.stringify(expected));
}

{
  const
    input = [
      { c: 1000, d: 4000 },
      { c: 2000, d: 5000 },
      { c: 3000, d: 6000 }
    ],
    expected = [
      [ 1000, 2000, 3000 ],
      [ 4000, 5000, 6000 ]
    ],
    actual = R.transpose(R.map(R.values, input));

  console.log(JSON.stringify(actual) === JSON.stringify(expected));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.29.0/ramda.min.js"></script>

0
Scott Sauyet On

If you can guarantee the same property order in your input objects, then this is quite pretty:

const collect = compose(transpose, map(values))

console.log(collect ([{a: 2000, b: 4000}, {a: 8000, b: 5000},{a: 6000, b: 1000}]))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.29.0/ramda.js"></script>
<script>const {compose, transpose, map, values} = R                  </script>

But if you can't, then you will have to do more work. While this works fine as a point-free version:

const collect = compose(transpose, chain(compose(map, props), compose(keys, head)))

console.log(collect([{a: 2000, b: 4000}, {a: 8000, b: 5000},{a: 6000, b: 1000}]))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.29.0/ramda.js"></script>
<script>const {transpose, chain, compose, map, props, keys, head} = R</script>

I find it less readable than the pointed version:

const collect = (input) => 
  transpose(map(props(keys(head(input))))(input))

console.log(collect([{a: 2000, b: 4000}, {a: 8000, b: 5000},{a: 6000, b: 1000}]))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.29.0/ramda.js"></script>
<script>const {transpose, chain, map, props, keys, head} = R         </script>

And, as Mr. Polywhirl points out, with a very simple custom transpose function, this can be done easily enough in vanilla JS.