Reputation: 855
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
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
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