1
\$\begingroup\$

Recently on Stack Overflow, a now deleted question was wondering how to convert one particular model of JSON that their code was outputting to another. The OPs main issue was that the JSON generated by their sheet_to_json (I assume it was some sort of CSV file) looked like so:

[
{ 'First name': 'A', 'Last Name': 'B', 'Some random number': 3 },
{ 'First name': 'C', 'Last Name': 'D', 'Some random number': 5 },
{ 'First name': 'E', 'Last Name': 'F', 'Some random number': 8 }
]

However, the model they wanted and what they send to the DB looked like so:

export interface SomeInterface {
 firstName: string,
 lastName: string,
 someRandomNumber: number
}

this got me thinking as to how a method that can convert one style to another would look like. After much trial and error, and googling, I came up with the following:

function mapData(state: any, mapper: Record<string, string>) {
  let final : SomeInterface []= [];
  state.forEach((x, i) => {
    
    
    let initialValue: any = {};
    let obj : any = {};

    let converted = Object.keys(x).map((z : string) => { 
          let mappedLabel = mapper[z];
          obj[mappedLabel] = (x as any)[z];

          return {...obj};      
      }, {}).reduce((obj2, item) => {
        return {
          ...obj2,
          [i]: item
        }
      }, initialValue)
    
//State before the below code is "0" : {..myModel}, "1": {...myModel}
// hence the extra object.keys to get the actual model that is behind the indexed key
    Object.keys(converted).forEach(x => {
      let actualObject = converted[x] as SomeInterface;
      final.push(actualObject);
    });
  });

  
  return final;
}

whereby state is the original object we wish to convert and mapper is the mapping of the original keys to the desired keys, ex:

const LABEL_TO_KEY: Record<string, string> = {
    'First name': 'firstName',
    'Last Name': 'lastName',
    'Some random number': 'someRandomNumber'
}

I've only really been professionally coding in TS/JS for ~2 years, so I am sure this is not the ideal state. If this were C# (my bread and butter for the past 5 years) then leveraging LINQ would make this be a very straight forward problem. I would love any constructive criticism

playground of my solution

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Disclaimer: I don't know Typescript, so this answer will be written in vanilla JS. However, it should be simple to add types to make it idiomatic TS.

To be honest, I have no idea what the code in let converted = ... is doing. It seems excessively complicated for the simple task of translating all of the keys in an object.

I decided to rewrite your code based on the problem description:

function mapData(state, mapper) {
  return state.map((x) => 
    Object.fromEntries(
      Object.entries(x).map((entry) => {
        let [key, value] = entry;
        return [mapper[key], value];
      })
    )
  );
}

Playground Link

Since we're transforming each element of the initial array, Array#map is what we should use, not Array#forEach, as it creates a new array by calling a transforming function on every element of the original array.

For the transforming function itself, essentially what we're doing is converting each object into an array of [key, value] entries with Object.enteries, mapping the key to the corresponding key in mapper by returning a [mapper[key], value] pair, and finally converting the array of key-value pairs back to an object with Object.fromEntries.

\$\endgroup\$
2
  • \$\begingroup\$ I think my converted is in essence an implementation of fromEntries since I legit forgot this method exists. \$\endgroup\$ Aug 23, 2022 at 19:35
  • \$\begingroup\$ Just a small remark: The arrow function could be simplified by moving the deconstruction to the parameters and using a expression body instead of a block with return: ([key, value]) => [mapper[key], value] \$\endgroup\$
    – RoToRa
    Aug 24, 2022 at 12:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.