thecartesianman
thecartesianman

Reputation: 855

Convert array of arrays to object of arrays, using ramda

Given an array of either 2d or 3d data. How can one create a function that converts the data to object of arrays, where the inner index maps to x, y or z depending on if the index is 0, 1 or 2 respectively. For example:

// 2d
const inputData2d = [
    [-1, 4],
    [3, 6],
    [9, -8],
]

const outputData2d = {
    x: [-1, 3, 9],
    y: [4, 6, -8],
}

// 3d
const inputData3d = [
    [-1, 4, 5],
    [3, 6, 2],
    [9, -8, 5],
]

const outputData3d = {
    x: [-1, 3, 9],
    y: [4, 6, -8],
    z: [5, 2, 5],
}

The function should also be able to handle both 2d and 3d data, behaving as expected. I've explored using pipe and assoc but no luck as of yet.

Upvotes: 0

Views: 317

Answers (2)

Ori Drori
Ori Drori

Reputation: 193057

With Ramda you can Transpose the array of arrays, and then use R.zipObj to combine it with the keys. R.zipObj truncates the zipped arrays to the shorter of the two, so you can supply ['x', 'y', 'z'], and it would be truncated to ['x', 'y'] for the 2d data.

const { pipe, transpose, zipObj } = R

const fn = pipe(transpose, zipObj(['x', 'y', 'z']))

const inputData2d = [[-1,4],[3,6],[9,-8]]
const inputData3d = [[-1,4,5],[3,6,2],[9,-8,5]]

console.log(fn(inputData2d))
console.log(fn(inputData3d))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

And the same idea works with lodash, although it's more verbose. You'll need to use _.unzip() instead of R.transpose, and pick keys with values using _.pickBy():

const { flow, unzip, zipObject, pickBy } = _

const fn = flow(
  unzip, 
  arr => zipObject(['x', 'y', 'z'], arr),
  obj => pickBy(obj)
)

const inputData2d = [[-1,4],[3,6],[9,-8]]
const inputData3d = [[-1,4,5],[3,6,2],[9,-8,5]]

console.log(fn(inputData2d))
console.log(fn(inputData3d))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

And you can remove some of the verboseness with Lodash/fp:

const { flow, unzip, zipObject, pickBy, identity } = _

const fn = flow(
  unzip, 
  zipObject(['x', 'y', 'z']),
  pickBy(identity)
)

const inputData2d = [[-1,4],[3,6],[9,-8]]
const inputData3d = [[-1,4,5],[3,6,2],[9,-8,5]]

console.log(fn(inputData2d))
console.log(fn(inputData3d))
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>

Upvotes: 2

Aadit M Shah
Aadit M Shah

Reputation: 74244

First, transpose the input and then zip it into an object.

const matrixToTransposedObject = R.compose(
    R.zipObj(["x", "y", "z"]),
    R.transpose
);

const inputData2d = [
    [-1, 4],
    [3, 6],
    [9, -8],
];

const outputData2d = matrixToTransposedObject(inputData2d);

console.log(outputData2d);

const inputData3d = [
    [-1, 4, 5],
    [3, 6, 2],
    [9, -8, 5],
];

const outputData3d = matrixToTransposedObject(inputData3d);

console.log(outputData3d);
<script src="https://unpkg.com/[email protected]/dist/ramda.min.js"></script>

Upvotes: 2

Related Questions