skip to Main Content

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

Answers


  1. 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>
    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search