7

This is my case.

data: [
    {
      q: "question 1",
      a: "answer 1"
    }, 
    {
      q: "question 2"
    }
]

How can I map this into key: value pair so that the final output is { "question 1": "answer 1"}?

The trick is that only if a property exists then it should be assigned to the new object as above example { "question N": "answer N"}.

I have tried combining .map() and .filter(), but it didn't work.

For example:

const obj = data.map(e => e.q).filter(s => s.a)

Thanks.

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
storagemode11
  • 875
  • 7
  • 11

6 Answers6

8

You need to filter element first and then map

let data = [{q: "question 1",a: "answer 1"},{q: "question 2"}]

const obj = data.filter(s => s.a)
                .map(({q,a}) => ({ [q]: a }))

console.log(obj)

Can we get output as object, you can use reduce and build an Object,

let data = [{q: "question 1",a: "answer 1"},{q: "question 2"}]

const obj = data.reduce((op,{q,a})=>{
  if( a ) op[q] = a
  return op
},{})

console.log(obj)

In modern browser you can Object.fromEntries too

let data = [{q: "question 1",a: "answer 1"},{q: "question 2"}]

const obj = Object.fromEntries(data.filter(s => s.a)
                .map(({q,a}) => [q,a]))

console.log(obj)
Code Maniac
  • 37,143
  • 5
  • 39
  • 60
  • Thanks, is it possible that this is object, so: `{ "question 1": "answer 1" }` – storagemode11 Oct 29 '19 at 17:59
  • 2
    @storagemode11 have a look at the second snippet – Code Maniac Oct 29 '19 at 18:03
  • @CodeManiac, Looks great, thanks. What if `obj` has some data, so we don't want to reassign to it, but instead just to append data? – storagemode11 Oct 29 '19 at 18:08
  • 1
    @storagemode11 you can merge two object. [`How to merge two objects in JS`](https://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically), and if obj is an array then you can simply concat values – Code Maniac Oct 29 '19 at 18:11
4

You can use map() and then filter().

let data = [{ q: "question 1", a: "answer 1" }, { q: "question 2" } ];

let result = data.map(item => {
  if (item.q && item.a) {
    return {
      [item.q]: item.a
    };
  }
}).filter(item => item); // Filter undefined values.

console.log(result);
Nikhil
  • 6,493
  • 10
  • 31
  • 68
  • 1
    [Code Maniac's answer](https://stackoverflow.com/a/58612968/1218980) does this, but better. Filtering first reduces the complexity of the mapping. – Emile Bergeron Oct 29 '19 at 17:59
  • Thanks, is it possible that this is object, so: `{ "question 1": "answer 1" }` – storagemode11 Oct 29 '19 at 18:00
  • @storagemode11 - If you have multiple items in array, then you'll get multiple objects. If you want to access just the first object you can do it as `result[0]`. – Nikhil Oct 29 '19 at 18:03
2

For a single object, you could take Object.fromEntries for creating a sigle object out of key/value pairs.

var data = [{ q: "question 1", a: "answer 1" }, { q: "question 2" }],
    result = Object.fromEntries(data
        .map(({ q, a }) => [q, a])
        .filter(([_, a]) => a)
    );

console.log(result);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

Using the reduce method effectively ensure u run a single loop with a conditional inside, instead of a map and a filter like the previous answers which are both definitely correct as well

let data = [{q: "question 1",a: "answer 1"},{q: "question 2"}]

const obj = data.reduce((acc,cur) => {
If(cur.a && cur.q) {
acc.push({[`${cur.q}`]: cur.a})
}. 
return acc
} ,[])

console.log(obj)
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
MiDas
  • 374
  • 1
  • 4
1

Here's what I believe you're trying to do, and this will account for multiple questions as well.

First, you need to use filter to get rid of anything that doesn't have the a property defined.

Then, you can use a reducer function.

This reducer accumulates a brand new object (starting with {} which is passed as the 2nd argument to reduce). It assigns each property (question name) to each value (answer) and returns the new accumulated variable, until it's done iterating.

const data = [{q: "question 1", a: "answer 1"}, {q: "question 2"}, {q: "question 3", a: "answer 3"}]

const obj = data.filter(item => item.hasOwnProperty('a'))
    .reduce(function(acc, cur) {
        acc[cur.q] = cur.a
        return acc 
    }, {})
Andrew
  • 763
  • 7
  • 21
-1

Here you go:

const obj = data.filter(s => s.a).map(e => ({[e.q]: e.a}))
Mo.
  • 26,306
  • 36
  • 159
  • 225
onetyone
  • 457
  • 4
  • 15
  • Why does one get downvoted for that, this is a perfectly correct answer and even more compact than most of the other ones. Anyone care to explain? – onetyone Oct 29 '19 at 18:06
  • 1
    Not the downvoter, but this is not having any difference with my answer, except some spacing removed. also code only answers are not considered as good practice on so – Code Maniac Oct 29 '19 at 18:08
  • 1
    It's the same thing as the top answer, but on oneline... It brings nothing new here. Code without explanation is another reason for a downvote. – Emile Bergeron Oct 29 '19 at 18:08
  • Why does similarity to the top answer make this one bad? Automatically assuming I stole the top answer's code? Original solutions often look similar for simple problems like this one. Talking about explanations, I suspected OP had the required background knowledge, though I kinda see your point. – onetyone Oct 29 '19 at 18:13
  • 2
    @onetyone I have not downvoted this either, but the problem is probably just with simply giving an answer without teaching anything. For the most part I don't think question askers are seeking merely solutions, but knowledge in general. Like, a great answer would not just give a solution, but would explain what the solution does, why the answerer has chosen such a methodology, and would perhaps directly quote and/or link to any applicable documentation, etc. – Andrew Oct 29 '19 at 18:23
  • You probably already knew everything I just said. I'm not trying to be condescending and hope I didn't come across as such. – Andrew Oct 29 '19 at 18:24
  • 1
    _"I don't think question askers are seeking merely solutions"_ It's not just about the asker, it's about the quality of the content as a whole. Since an answer like this brings nothing to the thread, even if it works, it won't be well received by the community. – Emile Bergeron Oct 29 '19 at 18:31