0

I have a function that will accept 3 arguments; an array of data, a key and a partial value. I want to group the results by a value that may be in each objects nested array. It looks like my code is working, but I'm wondering if refactoring to use reduce would be better. Here is what I have:

const arr = [
  {
    "id": "vghjnbghjkoijhjnmkjhjk",
    "region": "US",
    "tags": ["tag1:bvghjhgh","tag2:bvghjkjnm","tag3:vghjbghj"]
  },
  {
    "id": "cvbhyt56789-mnbvghyu76",
    "region": "US",
    "tags": ["tag1:bvghjhgh"]
  },
  {
    "id": "ghjkjnbhjnbhjkmnhjkmjk",
    "region": "US",
    "tags": ["tag2:bvghjkjnm"]
  },
  {
    "id": "ghjkjnbhjnbhjkmnhjkmjk",
    "region": "US",
    "tags": []
  },
  {
    "id": "bghjkjnbghjkjnhjnbhjhj",
    "region": "CA",
    "tags": ["tag1:bvghjhgh","tag3:vghjbghj"]
  }
];

The expected results are as follows, based on a key of tags and a value of tag1:

[
  [
    {
      "id": "vghjnbghjkoijhjnmkjhjk",
      "region": "US",
      "tags": ["tag1:bvghjhgh","tag2:bvghjkjnm","tag3:vghjbghj"]
    },
    {
      "id": "cvbhyt56789-mnbvghyu76",
      "region": "US",
      "tags": ["tag1:bvghjhgh"]
    },
    {
      "id": "bghjkjnbghjkjnhjnbhjhj",
      "region": "CA",
      "tags": ["tag1:bvghjhgh","tag3:vghjbghj"]
    }
  ],
  [
      {
        "id": "ghjkjnbhjnbhjkmnhjkmjk",
        "region": "US",
        "tags": ["tag2:bvghjkjnm"]
      },
      {
        "id": "ghjkjnbhjnbhjkmnhjkmjk",
        "region": "US",
        "tags": []
      },
  ]
]

Here is my current function:

function groupData(arr, key, value) {
  const grouped = {};
  const remaining = [];

  for (const obj of arr) {
    const index = obj[key].findIndex(elem => elem.includes(value));  
    if (index > -1) {
      const groupByKey = obj[key][index];
      if (grouped.hasOwnProperty(groupByKey)) {
        grouped[groupByKey].push(obj);
      } else {
        grouped[groupByKey] = [obj];
      }
    } else {
      remaining.push(obj);
    }
  }

  return [Object.values(grouped).flat(), noMatch];
}

2 Answers 2

2

I provide a solution using reduce() and map,but compared with other answers,seems groupby is a better choice

const arr = [
  {
    "id": "vghjnbghjkoijhjnmkjhjk",
    "region": "US",
    "tags": ["tag1:bvghjhgh","tag2:bvghjkjnm","tag3:vghjbghj"]
  },
  {
    "id": "cvbhyt56789-mnbvghyu76",
    "region": "US",
    "tags": ["tag1:bvghjhgh"]
  },
  {
    "id": "ghjkjnbhjnbhjkmnhjkmjk",
    "region": "US",
    "tags": ["tag2:bvghjkjnm"]
  },
  {
    "id": "ghjkjnbhjnbhjkmnhjkmjk",
    "region": "US",
    "tags": []
  },
  {
    "id": "bghjkjnbghjkjnhjnbhjhj",
    "region": "CA",
    "tags": ["tag1:bvghjhgh","tag3:vghjbghj"]
  }
];

let mdata = {'tags':'tag1'}
let entries = Object.entries(mdata).flat()
let key = entries[0],value = entries[1]

let result = arr.reduce((a,c) => {
 let exists = c[key].some(i => i.startsWith(value + ':'))
 let skey = exists ? value: 'other'
 let obj = a.find(a => a[skey])
 if(obj){
   obj[skey].push(c)
 }else{
   obj = {[skey]:[c]}
   a.push(obj)
 }
 return a
},[])

result = result.map(d => d[value]||d.other)
console.log(result)

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

Comments

0

A generic groupBy (similar functions exist in popular libraries like LoDash) would help here:

const groupBy = (iterable, keyFn) => {
    const groups = new Map();
    for (const x of iterable) {
        const key = keyFn(x);
        let group = groups.get(key);
        if (group === undefined) {
            groups.set(key, group = []);
        }
        group.push(x);
    }
    return groups;
};

Then you have:

const groupData = (arr, key, value) => {
    const groups = groupBy(arr, obj =>
        obj[key].find(elem => elem.includes(value)));

    const noMatch = groups.get(undefined);
    groups.delete(undefined);

    return [[...groups.values()].flat(), noMatch];
};

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.