3

I am trying to categorise the objects by comparing two objects say data and categories

const data = {
  "1a": {
    "name": "1a",
    "count": 154
  },
  "1b": {
    "name": "1b",
    "count": 765
  },
  "1c": {
    "name": "1c",
    "count": 7877
  },
  "777": {
    "name": "777",
    "count": 456
  }
};

const categories = {
    "A_category":["A","1a", "2a"],
    "B_category":["1b", "2b"],
    "C_category":["1c", "2c"],
    "D_category":["1d", "2d"]
};

I want to group the data based on the category object, when there is no match the group should be others and the resultant data should be like

const resultData = [
  { group: 'Others', name: '777', count: 456 },
  { group: 'A_category', name: '1a', count: 154 },
  { group: 'B_category', name: '1b', count: 765 },
  { group: 'C_category', name: '1c', count: 7877 }
]

I used the function but not able to achieve the result

const resultData = [];
function restructure(data, categories) {
  Object.keys(data).map(
    dataKey => {
      for (let [key, value] of Object.entries(categories)) {
      value.includes(dataKey) ? resultData.push({"group": key,...data[dataKey]}) : resultData.push({"group": "Others",...data[dataKey]})  ;
      break;
}
    }
  )
}

restructure(data,categories);
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73
ReNinja
  • 543
  • 2
  • 10
  • 27

3 Answers3

3

You can try this as well. Iterate over your data entries and find whether the key exists in any of the categories object data and push it into the array with found category as group or push it with Others as group as shown in the below code

const data = {
  "1a": {
    "name": "1a",
    "count": 154
  },
  "1b": {
    "name": "1b",
    "count": 765
  },
  "1c": {
    "name": "1c",
    "count": 7877
  },
  "777": {
    "name": "777",
    "count": 456
  }
};
    
const categories = {
  "A_category": ["A", "1a", "2a"],
  "B_category": ["1b", "2b"],
  "C_category": ["1c", "2c"],
  "D_category": ["1d", "2d"]
};

const resultData = [];

Object.entries(data).map(([key, val])=>{
    let group = Object.keys(categories).find(category=>categories[category].includes(key)) || 'Others'
    resultData.push({
        group,
        ...val
    })

})

console.log(resultData)
Dinesh Nadimpalli
  • 1,441
  • 1
  • 13
  • 23
1

Instead of for loop you need to use filter as let category = Object.entries(categories).filter(([key, value]) => value.includes(dataKey));.

If category.length > 0 then category is available else use Others.

Try it below.

const data = {
  "1a": {
    "name": "1a",
    "count": 154
  },
  "1b": {
    "name": "1b",
    "count": 765
  },
  "1c": {
    "name": "1c",
    "count": 7877
  },
  "777": {
    "name": "777",
    "count": 456
  }
};

const categories = {
  "A_category": ["A", "1a", "2a"],
  "B_category": ["1b", "2b"],
  "C_category": ["1c", "2c"],
  "D_category": ["1d", "2d"]
};

const resultData = [];

function restructure(data, categories) {
  Object.keys(data).map(
    dataKey => {
      let category = Object.entries(categories)
        .filter(([key, value]) => value.includes(dataKey));
      resultData.push({
        "group": category.length > 0 ? category[0][0] : "Others",
        ...data[dataKey]
      });
    })
}

restructure(data, categories);
console.log(resultData);
Karan
  • 12,059
  • 3
  • 24
  • 40
0

That's because you're breaking out of the loop regardless of whether you found the category or not. Your for loop will only execute once then breaks immediately. If the first category object matches, it is used, if not "Others" is assigned and the loop exits without checking the rest of the categories. Only break out of the loop if the lookup is successful:

for (let [key, value] of Object.entries(categories)) {
    if(value.includes(dataKey)) {                                  // if this is the category
        resultData.push({ "group": key, ...data[dataKey] });       // use it ...
        return;                                                    // ... and break the loop and the current iteration of forEach. The current object is handled
    }
}

resultData.push({ "group": "Others", ...data[dataKey] });          // if the return statement above is never reached, that means the category was not found, assign "Others"

BTW, you can use other array methods to shorten things out like so:

function restructure(data, categories) {
  return Object.keys(data).map(key => ({
      "group": Object.keys(categories).find(cat => categories[cat].includes(key)) || "Others",
      ...data[key]
  }));
}

Then use like so:

const resultData = restructure(data, categories);

My method uses find to try to find a category key that contains the name of the object, if find fails, it returns null at which point, the || "Others" part is evaluated and "Others" will be used as the group name (Does JavaScript have "Short-circuit" evaluation?).

Demo:

const data = {"777":{"name":"777","count":456},"1a":{"name":"1a","count":154},"1b":{"name":"1b","count":765},"1c":{"name":"1c","count":7877}};

const categories = {"A_category":["A","1a","2a"],"B_category":["1b","2b"],"C_category":["1c","2c"],"D_category":["1d","2d"]};

function restructure(data, categories) {
  return Object.keys(data).map(key => ({
      "group": Object.keys(categories).find(cat => categories[cat].includes(key)) || "Others",
      ...data[key]
  }));
}

const resultData = restructure(data, categories);

console.log(resultData);
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73