1

I have an array of objects I want to group/merge the objects which have similar branches and environments and concat their pools at the same time.

const data = [
  {
    branch: "master",
    environment: "dev",
    pool: "6g",
    service: "amex",
  },
  {
    branch: "master",
    environment: "dev",
    pool: "6g",
    service: "amex",
  },
  {
    branch: "feature/rest",
    environment: "dev",
    pool: "2g",
    service: "amex",
  },
  {
    branch: "master",
    environment: "dev",
    pool: "4g",
    service: "amex",
  },
  {
    branch: "hotfix/23",
    environment: "test",
    pool: "9g",
    service: "amex",
  },
  {
    branch: "hotfix/23",
    environment: "test",
    pool: "1g",
    service: "amex",
  },
];

I want the result in the below format removing duplicate objects as well I tried to reduce it but as array reduce returns a single object as a result and the other objects are being omitted from the response what data structure or way I can use to achieve the result?

const result = [
  {
    branch: "master",
    environment: "dev",
    pool: "6g, 4g",
    service: "amex",
  },
  {
    branch: "feature/rest",
    environment: "dev",
    pool: "2g",
    service: "amex",
  },
  {
    branch: "hotfix/23",
    environment: "test",
    pool: "9g,1g",
    service: "amex",
  },
];
4
  • try Array.map() Commented Jun 3, 2022 at 15:17
  • How i can compare two objects in map, in reduce i had accumulator and i can compare? Commented Jun 3, 2022 at 15:20
  • I recommend filtering your array based on each branch for exmaple master , and then work with new created arrays Commented Jun 3, 2022 at 15:24
  • Does this answer your question? How to group an array of objects based on multiple keys in Javascript? Commented Jun 3, 2022 at 15:44

5 Answers 5

5

const data = [{
    branch: "master",
    environment: "dev",
    pool: "6g",
    service: "amex",
  },
  {
    branch: "feature/rest",
    environment: "dev",
    pool: "2g",
    service: "amex",
  },
  {
    branch: "master",
    environment: "dev",
    pool: "4g",
    service: "amex",
  },
  {
    branch: "hotfix/23",
    environment: "test",
    pool: "9g",
    service: "amex",
  },
  {
    branch: "hotfix/23",
    environment: "test",
    pool: "1g",
    service: "amex",
  },
];

var cacheMix = {};

for (var i = 0; i < data.length; i++) {

  var item = data[i];
  var compositeKey = item.environment + "~" + item.branch;

  if (cacheMix[compositeKey]) {
    cacheMix[compositeKey].pools[item.pool] = 1;
  } else {
    var pools = {}; pools[item.pool] = 1; //to avoid dublicate pools 
    cacheMix[compositeKey] = {
      branch: item.branch,
      environment: item.environment,
      service: item.service,
      pools: pools 
    }
  }
}


var result = [];


for (var key in cacheMix) {

  var item = cacheMix[key];
  result.push({
    branch: item.branch,
    environment: item.environment,
    service: item.service,
    pool: Object.keys(item.pools).join(", ")
  });
}

console.log(result);

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

5 Comments

This approach loops just the minimal number of times through the items. For better performance never use array reduce
Reducing the time which developers will spend while trying to understand your code is, in most cases, much more important than some micro-optimalisation ;)
I don't know maybe I am the old school weirdo that reads it better this way
Thanks for the solution I think I just noticed is the input array also contains duplicates(same object twice) so the result object has the same pools concated for eg pool: 5g, 5g, 6g
That is very easy to fix just use object for pools and join the Object.keys(item.pools) at the end and no dublicates. Edited the code so it will not happen. I would appreciate if you mark the answer as correct so other developers of the community will not spend more time on this
2

Just create a dictionary out of them and fill in the values.

const data=[{branch:"master",environment:"dev",pool:"6g",service:"amex"},{branch:"feature/rest",environment:"dev",pool:"2g",service:"amex"},{branch:"master",environment:"dev",pool:"4g",service:"amex"},{branch:"hotfix/23",environment:"test",pool:"9g",service:"amex"},{branch:"hotfix/23",environment:"test",pool:"1g",service:"amex"},]


let x = {};
data.forEach(y => x[y.branch + "|" + y.environment] = y);

var res = Object.values(x).map(y => Object.assign({}, y)).map(y => 
{
    y.pool = data.filter(d => d.branch == y.branch && d.environment == y.environment).map(x => x.pool).join(",");
   return y;
})

If you do not care about immutability(original objects in data change), then remove Object.assign map and it will yield the same results

Comments

0

I'd suggest using Array.reduce() for this, creating a map of the data using a key created from the branch and environment.

Once we have the map object, we can use Object.values() to return an array of the desired results.

const data = [ { branch: "master", environment: "dev", pool: "6g", service: "amex", }, { branch: "feature/rest", environment: "dev", pool: "2g", service: "amex", }, { branch: "master", environment: "dev", pool: "4g", service: "amex", }, { branch: "hotfix/23", environment: "test", pool: "9g", service: "amex", }, { branch: "hotfix/23", environment: "test", pool: "1g", service: "amex", }, ];

const result = Object.values(data.reduce((acc, { branch, environment, pool, service }) => {
    // Our grouping key...
    const key = `${branch}-${environment}`;
    acc[key] = acc[key] || { branch, environment, pool: '', service };
    acc[key].pool += ((acc[key].pool ? ", " : "" ) + pool);
    return acc;
}, {}))

console.log('Result:', result)
.as-console-wrapper { max-height: 100% !important; }

Comments

0

This is one way to do it:

const data=[{branch:"master",environment:"dev",pool:"6g",service:"amex"},{branch:"feature/rest",environment:"dev",pool:"2g",service:"amex"},{branch:"master",environment:"dev",pool:"4g",service:"amex"},{branch:"hotfix/23",environment:"test",pool:"9g",service:"amex"},{branch:"hotfix/23",environment:"test",pool:"1g",service:"amex"},]

const res = data.reduce((acc, cur) =>
{
    let isMatch = false
    acc.forEach((el, idx) => {
        if(el.branch === cur.branch && el.environment === cur.environment) {
            if(acc[idx].service !== cur.service) {
                acc[idx].service += `, ${cur.service}`
            }
            if(acc[idx].pool !== cur.pool) {
                acc[idx].pool += `, ${cur.pool}`
            }
            isMatch = true
        }
    })
    if(!isMatch) {
        acc.push(cur)    
    }
    
    return acc
}, [])

console.log(res)

Comments

0
data.reduce((prev, curr) => {
  const container = prev.find(
    el => (el.branch === curr.branch) && (el.environment === curr.environment)
  );
  if (container) {
    container.pool = container.pool + `,${curr.pool}`
    return prev;
  } else {
    return prev.concat({...curr}) 
  }
}, [])

but I would suggest to instead create an object with keys equal to branch names.

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.