最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

How to ungroup an object array based on multiple array properties in Javascript - Stack Overflow

matteradmin5PV0评论

Think of an object array, each of them having certain array properties like versions, targets. I want to ungroup objects for each version and target.

const myArray = [
  { 'name': 'a', versions: [1, 2], targets: ['server1', 'server2']},
  { 'name': 'b', versions: [], targets: ['server1', 'server2', 'server3']},
  { 'name': 'c', versions: [1], targets: []}
]

Desired output for myArray above would be:

[
  { 'name': 'a', version: 1,         target: 'server1'},
  { 'name': 'a', version: 1,         target: 'server2'},
  { 'name': 'a', version: 2,         target: 'server1'},
  { 'name': 'a', version: 2,         target: 'server2'},
  { 'name': 'b', version: undefined, target: 'server1'},
  { 'name': 'b', version: undefined, target: 'server2'},
  { 'name': 'b', version: undefined, target: 'server3'},
  { 'name': 'c', version: 1,         target: undefined},
]

I pondered using nested for/forEach loops, but am almost pretty sure there must be a more precise and reasonable way of achieving it built-in es6 functions or so. And that's what I'm asking for.

Think of an object array, each of them having certain array properties like versions, targets. I want to ungroup objects for each version and target.

const myArray = [
  { 'name': 'a', versions: [1, 2], targets: ['server1', 'server2']},
  { 'name': 'b', versions: [], targets: ['server1', 'server2', 'server3']},
  { 'name': 'c', versions: [1], targets: []}
]

Desired output for myArray above would be:

[
  { 'name': 'a', version: 1,         target: 'server1'},
  { 'name': 'a', version: 1,         target: 'server2'},
  { 'name': 'a', version: 2,         target: 'server1'},
  { 'name': 'a', version: 2,         target: 'server2'},
  { 'name': 'b', version: undefined, target: 'server1'},
  { 'name': 'b', version: undefined, target: 'server2'},
  { 'name': 'b', version: undefined, target: 'server3'},
  { 'name': 'c', version: 1,         target: undefined},
]

I pondered using nested for/forEach loops, but am almost pretty sure there must be a more precise and reasonable way of achieving it built-in es6 functions or so. And that's what I'm asking for.

Share Improve this question asked Dec 18, 2019 at 7:36 vahdetvahdet 6,75910 gold badges62 silver badges116 bronze badges 1
  • 1 There isn't a native method that I know of off-the-bat: I guess that's because what you're seeing essentially is creating all possible binations of versions + targets. That would call for a basic for loop, and it will grow in plexity the more dimensions you have, since the more nested the loops will have to be. – Terry Commented Dec 18, 2019 at 7:39
Add a ment  | 

4 Answers 4

Reset to default 6

You could use .flatMap:

  const notEmpty = arr => arr.length ? arr : [undefined];

  myArray.flatMap(({ name, versions, targets }) => notEmpty(versions).flatMap(version => notEmpty(targets).map(target => ({ name, version, target }))));

Or with more dimensions, generators get very useful:

  function* cartesian(obj, key, ...keys) {
     if(!key) {
         yield obj;
         return;
     }

    const { [key + "s"]: entries, ...rest } = obj;
    for(const entry of (entries.length ? entries : [undefined])) {
        yield* cartesian({ [key]: entry, ...rest }, ...keys);
     }
 }

 myArray.flatMap(it => cartesian(it, "version", "target"))

You can use reduce method:

const result = myArray.reduce((a, {name, versions, targets}) => {
  versions.forEach((el, ind) => {
      a.push({name, version: versions[ind], target: targets[ind]})
  });
  targets.forEach((el, ind) => {
      a.push({name, version: versions[ind], target: targets[ind]})
  });  
  return a;    
}, []);

An example:

const myArray = [
  { 'name': 'a', versions: [1, 2], targets: ['server1', 'server2']},
  { 'name': 'b', versions: [], targets: ['server1', 'server2', 'server3']},
  { 'name': 'c', versions: [1], targets: []}
]


const result = myArray.reduce((a, {name, versions, targets}) => {
  versions.forEach((el, ind) => {
      a.push({name, version: versions[ind], target: targets[ind]})
  });
  targets.forEach((el, ind) => {
      a.push({name, version: versions[ind], target: targets[ind]})
 });  
  return a;
}, []);

console.log(result);

const myArray = [
  { 'name': 'a', versions: [1, 2], targets: ['server1', 'server2'] },
  { 'name': 'b', versions: [], targets: ['server1', 'server2', 'server3'] },
  { 'name': 'c', versions: [1], targets: [] }
]

const reducer = (acc, current) => {
  const { name, versions, targets } = current;
  for (let i = 0; i < versions.length; i++) {
    acc.push({ name, version: versions[i], target: targets[i] })
  }

  for (let i = 0; i < targets.length; i++) {
    acc.push({ name, version: versions[i], target: targets[i] })
  }

  return acc;
}

const ungroup = array => array.reduce(reducer, [])

console.log(ungroup(myArray))

We can Un group the objects in the following way

const rows = [
  {
"groupId": "ff686b1c-0d83-4e9e-ac0e-edd4ed7a1579",
"clientName": "Apple",
"Id": 110117,
"manageFunds": [
  {
    "accountId": "eb9e38a8-2e0e-46c2-b50a-fa5c7c18ea53",
    "address": {
      "address1": "",
      "city": "",
      "state": "",
      "zipcode": "",
      "country": ""
    }
  },
  {
    "accountId": "eb9e38a8-2e0e-46c2-b50a-fa5c7c18ea54",
    "address": {
      "address1": "",
      "city": "",
      "state": "",
      "zipcode": "",
      "country": ""
    }
  }
],
"size": 2,
"bulkUploadErrorMessage": ""
  },
  {
"groupId": "ff686b1c-0d83-4e9e-ac0e-edd4ed7a1589",
"clientName": "Mango",
"Id": 110118,
"manageFunds": [
  {
    "accountId": "eb9e38a8-2e0e-46c2-b50a-fa5c7c18ea55",
    "address": {
      "address1": "",
      "city": "",
      "state": "",
      "zipcode": "",
      "country": ""
    }
  },
  {
    "accountId": "eb9e38a8-2e0e-46c2-b50a-fa5c7c18ea56",
    "address": {
      "address1": "",
      "city": "",
      "state": "",
      "zipcode": "",
      "country": ""
    }
  }
],
"size": 2,
"bulkUploadErrorMessage": ""
  },
  {
"groupId": "ff686b1c-0d83-4e9e-ac0e-edd4ed7a1599",
"clientName": "Orange",
"Id": 110119,
"manageFunds": [
  {
    "accountId": "eb9e38a8-2e0e-46c2-b50a-fa5c7c18ea57",
    "address": {
      "address1": "",
      "city": "",
      "state": "",
      "zipcode": "",
      "country": ""
    }
  },
  {
    "accountId": "eb9e38a8-2e0e-46c2-b50a-fa5c7c18ea58",
    "address": {
      "address1": "",
      "city": "",
      "state": "",
      "zipcode": "",
      "country": ""
    }
  },
  {
    "accountId": "eb9e38a8-2e0e-46c2-b50a-fa5c7c18ea59",
    "address": {
      "address1": "",
      "city": "",
      "state": "",
      "zipcode": "",
      "country": ""
    }
  }
],
"size": 3,
"bulkUploadErrorMessage": ""
  }
]

const mergeMF = input => {
const initObj = []
input.forEach(rootItem => {
    const { Id, clientName, manageFunds } = rootItem
    const groupId = rootItem.groupId
    manageFunds.forEach(subItem => {
        const newSubItem = {
            ...subItem,
            accountId: subItem.accountId,
            Id: Id,
            clientName: clientName,
            groupId: groupId,
        }
        initObj.push({
            checked: false,
            data: newSubItem,
            isCollapsed: false,
            validationErrors: subItem.errorMessages
        })
    })
})
return initObj
}

console.log(mergeMF(rows))

Post a comment

comment list (0)

  1. No comments so far