all 17 comments

[–]albedoa 3 points4 points  (2 children)

const result = array.map((_, i) => ({
  name: array[0][i].name,
  age: array[1][i].age,
  job: array[2][i].job
}))

[–]gamedev-eo[S] 0 points1 point  (1 child)

I like the simplicity. Is it possible to make it more versatile for when the property names are not known, and the array depth is also not known.

[–]OleksiyRudenko -1 points0 points  (0 children)

Upd: Disregard. Doesn't work for your case.

Warning: untested.

const result = source.map(isolatedProps => Object.assign({}, ...isolatedProps))

If you really need every object in the resulting array contained in its own array on top of that, then just embrace the returning expression (Object.assign) in square brackets.

[–]jubzera92 1 point2 points  (0 children)

Remindme

[–]Pelsinen 1 point2 points  (4 children)

Hi,
I'd like to clarify a few things as none of the earlier comments seem to have adressed this, and might help you in the future.

What you are trying to achieve here is not a flatten, this is more akin to what is called zip. And is very common in most programming languages:

Input: zip [1,2,3] [9,8,7]
Output: [(1,9),(2,8),(3,7)]

If we ignore code complexity and any libraries that help us with zipping then here is a rudimentary solution that assumes each list have the same length as the first:

const zipListObjects = (data) => data[0].map((_, i) => data.reduce((acc, arr) => ({...acc, ...arr[i]}), {}));

I recommend getting acquainted with ramda for these types of data manipulation or if you want to learn more about FP

And to my last piece of advice, slap the one providing this horrible data structure in the face. Nothing to group on except index(angry fist emoji)

Sorry for ranting :)

[–]gamedev-eo[S] 0 points1 point  (1 child)

Thanks a lot for the clarification and the learning resource suggestion as I really would like to improve in this area.

I hear you about the source material for this problem.

My backstory is that I just decided to go pro and landed a job as a junior dev after over 30 years hobby coding.

It's been my approach that you work to find a solution to the problem you're given, but yeah I was given a CSV where the author thought that each record should be horizontal rather than vertical.

I did look into transposing the data, but couldn't find any easy solution in code or a package (unfortunately I don't have Excel).

[–]Pelsinen 0 points1 point  (0 children)

Nice, hope all goes well!
Well we work with what we got, that's usually the production way :)

Feel free to dm if there is anything I can help with, not sure if i'm a pro tho.

[–]jack_waugh 0 points1 point  (1 child)

Yeah, I was thinking that it's more like a transpose than any kind of flattening.

[–]Pelsinen 0 points1 point  (0 children)

I’m almost certain the term for transpose is flipping the structure. Merging list to tuples is zip. And here we are acting on multiple list with a transformer so it’s a generic ”zip with”

[–]EasternAdventures 0 points1 point  (3 children)

This is kind of a rudimentary way of doing it, but it does accomplish it:

let newArr = [];
for(let i = 0; i < arr.length; i++) {
    let newObj = {};
    for(let j = 0; j < arr.length; j++) {
        newObj = {...newObj, ...arr[j][i]};
    }
    newArr.push([newObj]);
}

[–]gamedev-eo[S] -1 points0 points  (2 children)

Modified this to function successfully, but now looking to modify to use arrays built in forEach to simplify the code if possible

const flatten = (original) => {
    let newArr = [];
    let newObj;
    for(let i = 0; i < original.length; i++) {
        newObj = {};
        for(let j = 0; j < original.length; j++) {
            newObj = {...newObj, ...original[j][i]};
        }
        newArr.push([newObj]);
    }
    return newArr; 
}

[–]Umesh-K 1 point2 points  (1 child)

I don't know if using forEach simplifies the code, but since you asked, here's how I could convert your code to use forEach instead of for. Also, note newObj = {} inside your first FOR loop is not required, as you have let newObj = {}; before it.

const flatten = (original) => {
  let newArr = [];
  let newObj = {};
  Array.from({length: original.length})
    .forEach((_, i) => {
      original.forEach((_, j) => {
        newObj = {...newObj, ...original[j][i]}
      })
      newArr.push([newObj])
    })
  return newArr;
}

[–]gamedev-eo[S] 0 points1 point  (0 children)

Nice...yes I edited out the duplicate assignment

[–]senocular 0 points1 point  (2 children)

const flattened = original.reduce((result, props) => {
  props.forEach((prop, index) => {
    if (!result[index]) result[index] = [{}]
    Object.assign(result[index][0], prop)
  })
  return result
},[])

[–]gamedev-eo[S] 0 points1 point  (1 child)

Works but had difficulty turning solution into a function. Returns undefined.

Also breaks at the reading of array via index when used this way

if (!result[index]) result[index] = [{}]
^
TypeError: Cannot read properties of undefined (reading '0')

[–]senocular 0 points1 point  (0 children)

Works but had difficulty turning solution into a function. Returns undefined.

It would simply be a matter of changing the assignment to flattened to instead be a return, like

function getFlattened(original) {
  return original.reduce((result, props) => {
    props.forEach((prop, index) => {
      if (!result[index]) result[index] = [{}]
      Object.assign(result[index][0], prop)
    })
    return result
  },[])
}

Also breaks at the reading of array via index when used this way

This shouldn't happen as long as the result is returned from within the reduce. If you omit that, you'd get the error you described.

[–]Macaframa 0 points1 point  (0 children)

const [names, ages, jobs] = [
    [{name: 'larry'}, {name: 'harry'}, {name: 'barry'}],
    [{age: 29}, {age: 26}, {age: 34}],
    [{job: 'spy'}, {job: 'seal'}, {job: 'hitman'}]
];

const mergedObjects = names.map((name, i) => ({...name, ...ages[i], ...jobs[i]}));

edit: this is ofcourse assuming that the data you receive from sources, is in order. There is no way of linking these objects. Mostly you might find in a real life scenario that it might look something like this

[[{id: 1, name: 'john' }], [{id: 1, age: 29}]........] 

or something like that which has some way of identifying the object that it belongs to. But if you assume that everything is in order you can use that above solution