1

Let me explain my problem.

I have data like :

data: {
  carType:  {key: 'sport',     label: 'Sports Car'},
  carStyle: {key: 'striped',   label: 'Striped (with blabla)'},
  carPrice: {key: 'expensive', label: 'Above 500.000$'},
  carOptions: [
    {key: 'aluminium',   label: 'Chrome Wheel (Available different size)'},
    {key: 'leatherSeat', label: 'Seat Leather from Italy'},
  ]
}

I would need to process this data in order to get the key-values associated with my object key/// The tricky case i'm facing here, is in the case of the multiple choice.

Something like :

body: {
 carType: 'sport',
 carStyle: 'striped',
 carPrice: 'expensive',
 carOptions: ['aluminium', 'leatherSeat']
}

I did something quite verbose in ES5. I'd like, if possible, something cleaner to use with the ES6/ES7 feature to solve this. Thanks for your time.

ps: Do not take in account the content of the data. It was made up for this topic. Only the data structure cannot be modified in my case.

9
  • I would like to know if I don't understand what the problem actually is because I'm still a little sick (it affects my head) or because it's really hard to understand? Commented Nov 21, 2017 at 14:53
  • Hi Morre. I just tried to provide some context. But you can just ignore it and try to find a way to pass from the first dataset to the second one :) Commented Nov 21, 2017 at 14:54
  • Ah, so you want to extract the keys. Well, map or reduce over the array of Object.keys and do the extraction in the callback function.... single key: obvious, array of objects: another map or reduce on the inner array. Commented Nov 21, 2017 at 14:55
  • Is this supposed to be a string to parse or a javascript object? this is not valid javascript syntax Commented Nov 21, 2017 at 14:55
  • My bad Axnyff. I did update my question Commented Nov 21, 2017 at 14:56

5 Answers 5

1

Here you in ES6, using Array.reduce

const data = {
  carType: {
    key: 'sport',
    label: 'Sports Car'
  },
  carStyle: {
    key: 'striped',
    label: 'Striped (with blabla)'
  },
  carPrice: {
    key: 'expensive',
    label: 'Above 500.000$'
  },
  carOptions: [{
      key: 'aluminium',
      label: 'Chrome Wheel (Available different size)'
    },
    {
      key: 'leatherSeat',
      label: 'Seat Leather from Italy'
    },
  ]
};

const changedData = Object.keys(data).reduce((tmp, x) => {
  tmp[x] = data[x] instanceof Array ? data[x].map(y => y.key) : data[x].key;

  return tmp;
}, {});

console.log(changedData);

Sign up to request clarification or add additional context in comments.

8 Comments

There's no reason to assign tmp to ptr?
Just got same discussion elsewhere in SO :p It's all about the eslint no-param-reassign rule.
That's a horrible workaround. You rather should explicitly disable the rule for that function if you want to violate it.
This is not a workaround, look at second example in the eslint documentation. This is actually what they do. You can disable the rule if you want to.
Actually that seems better
|
0

Well with ES5 you can loop over the data object keys, and construct your new body object by testing over ech iterated key:

Object.keys(data).forEach(function(k) {
  if (!Array.isArray(data[k])) {
    body[k] = data[k].key;
  } else {
    body[k] = data[k].map(function(opt) {
      return opt.key;
    });
  }
});

Demo:

var data = {
  carType: {
    key: 'sport',
    label: 'Sports Car'
  },
  carStyle: {
    key: 'striped',
    label: 'Striped (with blabla)'
  },
  carPrice: {
    key: 'expensive',
    label: 'Above 500.000$'
  },
  carOptions: [{
      key: 'aluminium',
      label: 'Chrome Wheel (Available different size)'
    },
    {
      key: 'leatherSeat',
      label: 'Seat Leather from Italy'
    },
  ]
};

var body = {};

Object.keys(data).forEach(function(k) {
  if (!Array.isArray(data[k])) {
    body[k] = data[k].key;
  } else {
    body[k] = data[k].map(function(opt) {
      return opt.key;
    });
  }
});

console.log(body);

4 Comments

carType and carStyle should work the same as carPrice
@Bergi Yes it's in eS5, I wanted to show that it's almost the same thing, and I edited the logic, thank you.
I'd like it generic. How would that works with 10-20-50-100 more lines similar to carOptions.
@LouisLecocq You can use the Array.isArray() like in Bergi's answer to make it generic.
0

You can use cleaner and readable functions and manipulation methods provided by ES6. Here is something ES6 helps to solve your problem

var data = {
  carType:  {key: 'sport',     label: 'Sports Car'},
  carStyle: {key: 'striped',   label: 'Striped (with blabla)'},
  carPrice: {key: 'expensive', label: 'Above 500.000$'},
  carOptions: [
    {key: 'aluminium',   label: 'Chrome Wheel (Available different size)'},
    {key: 'leatherSeat', label: 'Seat Leather from Italy'},
  ]
}
var obj = {};
Object.entries(data).forEach(([key, value]) => {
Object.defineProperty(obj, key, {
  value: Array.isArray(value) ? value.map(a => a.key) : value.key,
  writable: true,
  enumerable: true,
  configurable: true
});
});
console.log(obj)

5 Comments

No it won't. Checkout Object.entries() Mozilla docs developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Thanks for the effort though. Nice approach
Why do you use Object.defineProperty over a dead simple assignment?
just for fun ? or may be to play with `es6. #sorry
0

There's no much you can do better in ES6 than in ES5:

const data = …;
const body = {};
for (const p in data)
    body[p] = Array.isArray(data[p])
      ? data[p].map(x => x.key)
      : data[p].key;

For comparison, using the most recent features (including experimental object spread syntax), you could do

const body = Object.entries(data).reduce((res, [p, val]) => ({
    ...res,
    [p]: Array.isArray(val)
       ? val.map(({key}) => key)
       : val.key
}), {});

6 Comments

And now add a reduce based version for the object so that he gets to see all the fancy ES6/7 stuff that is all the rage these days and that he seems to want to see :-)
You can use a ternary there. Thanks though
@Mörre No, I consciously decided against that - it's slower, less readable, and more complicated. You can post it in your own answer for comparison :-)
@LouisLecocq Ah, another line saved.
Alright. I hoped someone would come with the next syntax ES6/ES7. I guess not everyone's looking for it yet. Will accept @Bergi. Thanks
|
0

if you are using lodash you can solution (1) in one line:

_.map(data, (element, index) => Array.isArray(element)?element.map(e=>e.key):element.key)

if you don't like ternary you can use solution (2) instead:

_.map(data, (element, index) => {
    if(Array.isArray(element)) {
        return element.map(e=>e.key)
    } else {
        return element.key
    }
})

and if you do not like lodash but you still want to use functional programing you can use solution (3):

Object.keys(data).reduce((accumulator, key) => {
    if(Array.isArray(accumulator[key])) {
        accumulator[key] = data[key].map(e=>e.key)
    } else {
        accumulator[key] = data[key].key
    }
    return accumulator
},{})

My opinion is to use solution (1) or (2) using lodash because it has (almost) the same syntax as Array native methods.

Using ternary or not is up to you, as well as using conventional loops or not

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.