2

I have the following code:

const blueData = {
    "items": [
        {
            "id": 35,
            "revision": 1,
            "updatedAt": "2021-09-10T14:29:54.595012Z",
        },
    ]
}

const redData = {}

const greenData = {
    "items": [
        {
            "id": 36,
            "revision": 1,
            "updatedAt": "2021-09-10T14:31:07.164368Z",
        }
    ]
}

let colorData = []
colorData = blueData.items ? [colorData, ...blueData.items] : colorData
colorData = redData.items ? [colorData, ...redData.items] : colorData
colorData = greenData.items ? [colorData, ...greenData.items] : colorData

I am guessing the spread operator is not the right approache here as I'm getting some extra arrays in my final colorData array. I simply want to build a single array of 'items' that contains all of the 'items' from the 3 objects.

Here's a link to that code in es6 console: https://es6console.com/ktkhc3j2/

5 Answers 5

2

Put your data into an array then use flatMap to unwrap each .items:

[greenData, redData, blueData].flatMap(d => d.items ?? [])
//=> [ {id: 36, revision: 1, updatedAt: '2021-09-10T14:31:07.164368Z'}
//=> , {id: 35, revision: 1, updatedAt: '2021-09-10T14:29:54.595012Z'}]

If you fancy you could abstract d => d.items ?? [] with a bit of curry (no pun intended ;)

const take = k => o => o[k] ?? [];

Which gives us:

[greenData, redData, blueData].flatMap(take('items'))

We can even go a step further if you ever need to repeat this process with different keys:

const concatBy = fn => xs => xs.flatMap(x => fn(x));

Now it almost feels like you're expressing your intent with words instead of code:

const takeItems = concatBy(take('items'));

takeItems([greenData, redData, blueData]);
//=> [ {id: 36, revision: 1, updatedAt: '2021-09-10T14:31:07.164368Z'}
//=> , {id: 35, revision: 1, updatedAt: '2021-09-

Let's build another function:

const takeFood = concatBy(take('food'));

takeFood([{food: ['🥑', '🥕']}, {food: ['🌽', '🥦']}]);
//=> ['🥑', '🥕', '🌽', '🥦']

Addendum

This is only meant as a potentially useful learning material. My advice is to use flatMap.

This:

[[1, 2], [3, 4]].flatMap(x => x)
//=> [1, 2, 3, 4]

Can also be expressed with reduce. Slightly more verbose but does what it says on the tin:

[[1, 2], [3, 4]].reduce((xs, x) => xs.concat(x), [])
//=> [1, 2, 3, 4]

So to put it simply you could also do:

[greenData, redData, blueData].reduce((xs, x) => xs.concat(x.items ?? []), [])
Sign up to request clarification or add additional context in comments.

Comments

1

You can do this using the Logical OR operator which lets you provide a default value if the items field is missing.

const blueData = { items: [ { id: 35, revision: 1, updatedAt: '2021-09-10T14:29:54.595012Z', }, ], };
const redData = {};
const greenData = { items: [ { id: 36, revision: 1, updatedAt: '2021-09-10T14:31:07.164368Z', }, ], };

const colorData = [
  ...(blueData.items || []),
  ...(redData.items || []),
  ...(greenData.items || []),
];

console.log(colorData);

Comments

1

Maybe I'm a little old-fashioned but I'd use concat for that:

The concat() method is used to merge two or more arrays. This method does not change the existing arrays, but instead returns a new array. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat

const blueData = {
    "items": [
        {
            "id": 35,
            "revision": 1,
            "updatedAt": "2021-09-10T14:29:54.595012Z",
        },
    ]
}

const redData = {}

const greenData = {
    "items": [
        {
            "id": 36,
            "revision": 1,
            "updatedAt": "2021-09-10T14:31:07.164368Z",
        }
    ]
}


const colorData = [].concat(blueData.items,redData.items,greenData.items).filter(x => x)

console.log(colorData)

the last filter is for removing undefined values

Comments

0

Like this?

colorData = blueData.items ? [...colorData, ...blueData.items] : colorData
colorData = redData.items ? [...colorData, ...redData.items] : colorData
colorData = greenData.items ? [...colorData, ...greenData.items] : colorData

Output:

[{"id":35,"revision":1,"updatedAt":"2021-09-10T14:29:54.595012Z"}, 
{"id":36,"revision":1,"updatedAt":"2021-09-10T14:31:07.164368Z"}]

I think you need to add the spread operator also to the colorData array, because if not you are adding the colorData array itself, not its items.

2 Comments

This is perfect (just have to wait a few minutes before accepting your answer). Is there a shorter way to write: colorData = blueData.items ? [...colorData, ...blueData.items] : colorData so that colorData just remains colorData if the ternary conditional is false?
you can have a look to the Nullish coalescing operator. Chaging the || by the ?? you check specifically for null or undefined values, instead of any falsy values in which null and undefined are included ;)
0

If you want the simplest solution, you can iterate with a for-loop between all arrays. Create a temporary array that will store data found on each index. This is the fastest and the most flexible solution.

var x1 = {
  "items": [
    { "testKey1": "testVal" }
  ] 
};

var x2 = {
  "items": [
    { "testKey2.0": "testVal2" },
    { "testKey2.1": "testVal2" },
    { "testKey2.2": "testVal2" },
  ] 
};

var x3 = {
  "items": [
    { "testKey3.0": "testVal3" },
    { "testKey3.1": "testVal3" }
  ] 
};

function combineArrays(...arrays) {

  var tempArray = [];
  for (let index in arrays) {
    let currentArray = arrays[index];
    for (let innerArrayIndex in currentArray) {
      tempArray.push(currentArray[innerArrayIndex]);
    }
  } 
  
  return tempArray;
}

var result = combineArrays(x1.items, x2.items, x3.items);
console.log(result);

The solutions using a spread operator do not take into consideration that all the objects will be cloned using a shallow copy. Have a look.

3 Comments

I think the OP is more after the solution for the specific problem and readability, anyhow very nice article + pokemon examples! :)
The solutions using a spread operator do not take into consideration that all the objects will be cloned using a shallow copy. — I'm not sure why you say that; your current solution doesn't clone anything at all. Not saying it's wrong though! Only an observation that your solution isn't mutation-proof either.
@customcommander If you want to be mutation-proof you can shallow copy (clone) the resulting array. Cloning each array and then merging seems to me like an overhead.

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.