1

I have array in javascript. i need count of parent id. like id 1 is parent of id 2 and id 2 is parent of id 3 & id 6 , id3 is parent of id 4 and id 4 is parent of id 5. so total count for id is 5.

var arr = [{ "Id": "1", "Parent": "1"},
{ "Id": "2",  "Parent": "1" },
{ "Id": "3",  "Parent": "2"},
{ "Id": "4",  "Parent": "3"},
{ "Id": "5",  "Parent": "4"}, 
{ "Id": "6",  "Parent": "2"}];

i need result like :

[{ "Id": "1", count :5},
{ "Id": "2",  "count": "4" },
{ "Id": "3",  "count": "2"},
{ "Id": "4",  "count": "1"},
{ "Id": "5",  "count": "0"},
{ "Id": "6",  "count": "0"}];

Here is my Fiddle jsfiddle.net/h5g30bhs

6
  • 1
    what have you tried so far? Commented Apr 30, 2018 at 11:03
  • i have tried all the things like this code. Commented Apr 30, 2018 at 11:07
  • jsfiddle.net/h5g30bhs Commented Apr 30, 2018 at 11:08
  • the intended result is not quite clear to me. only the first object has a count property, is this intended or a copy paste error? Commented Apr 30, 2018 at 11:16
  • [{ "Id": "1", count :5}, { "Id": "2", "count": "4" }, { "Id": "3", "count": "2"}, { "Id": "4", "count": "1"}, { "Id": "5", "count": "0"}, { "Id": "6", "count": "0"}]; Commented Apr 30, 2018 at 11:25

3 Answers 3

1

Create an area of objects with count getter using Array.reduce(), and Object.values(), then use Array.map() to create an object by invoking the getter.

Utility:

  • createCountObj - creates an object with the count getter

const arr = [{"Id":"1","Parent":"1"},{"Id":"2","Parent":"1"},{"Id":"3","Parent":"2"},{"Id":"4","Parent":"3"},{"Id":"5","Parent":"4"},{"Id":"6","Parent":"2"}];

// create a count object with children and count getter
const createCountObj = (Id) => ({
  Id,
  children: [],
  get count() {
    // optimization to use cached _count instead of recalculating
    this._count = '_count' in this ? this._count : 
      this.children.length + this.children.reduce((s, { count }) => s + count, 0);
    return this._count;
  }
});
const result = Object.values(arr.reduce((r, o) => {
    // take object if exists, or create new one if not
    r[o.Id] = r[o.Id] || createCountObj(o.Id);
    
    // if the object is not parent of itself
    if (o.Id !== o.Parent) {
      // create a parent if doesn't exist
      if(!r[o.Parent]) r[o.Parent] = createCountObj(o.Parent);
      
      // add to parent
      r[o.Parent].children.push(r[o.Id]);
    } 

    return r;
  }, {}))
  // create final objects by calling the getter of each item
  .map(({ Id, count }) => ({
    Id,
    count
  }));

console.log(result);

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

1 Comment

Lovely way to define a getter on object literal, learn something new every day.
0

The following will do it, if you need help then please let me know.

const arr = [
  { "Id": "1", "Parent": "1"},
  { "Id": "2",  "Parent": "1" },
  { "Id": "3",  "Parent": "2"},
  { "Id": "4",  "Parent": "3"},
  { "Id": "5",  "Parent": "4"}, 
  { "Id": "22",  "Parent": "22"},//added root item with no children
  { "Id": "6",  "Parent": "2"}
];

const reGroup = data => {
  const grouped = data.filter(x=>x.Id!==x.Parent).reduce(//only child items (id!==Parent)
    (o,item)=>{
      o[item.Parent]=o[item.Parent]||{count:0,children:[]};
      o[item.Parent].count+=1;
      o[item.Id]={count:0,children:[]};
      o[item.Parent].children.push(o[item.Id]);
      return o;
    },
    data.filter(x=>x.Id===x.Parent).reduce(//only root items (Id===Parent)
      (all,item)=>{
        all[item.Id]={count:0,children:[]};
        return all;
      },
      {}
    )
  );//you can console.log(grouped) if you wonder what it is
  const getSum = (item) => {//recursive function to get sum of item.children[x].children[x].count
    return item.children.reduce(
        (sum,item)=>sum+getSum(item),
        item.count
      );
  }
  return Object.keys(grouped).map(
    key=>({Id:key,count:getSum(grouped[key])})
  );
}
console.log(
  reGroup(arr)
  .map(JSON.stringify).join("\n")//add map to make the console log look better
);

3 Comments

Thank you so much.. you saved my day. thanks a lot. but i will more thankful if you can do it my more simple way to understand cause i am new at javascript.
@Coder what part don't you understand? Your data is reduced to an object like {"1":{"count":1,"children":[{"count":2,"children":[{"count":1,"children":[{"cou... Then for each key in this grouped object we create an object {Id:key,count:sum(objectItem)}
@Coder ...continuing: where sum recursively calls itself to get count and all children children children's count. if you would like the code to be simpler than you should try and fix a simpler problem maybe?
0

I gave this a shot. See if it works for you:

function convert(input) {
var output = [];
  input.forEach(i => {
    var node = output.find(o => o.Id === i.Parent);
    if (node !== undefined) {
      node.count = "" + (parseInt(node.count, 10) + 1);
    } else {
      output.push({Id: i.Parent, count: "1"})
    }
  })
  return output;
}

A few things to consider:

  • your properties should probably all start with a lowercase letter (id instead of Id)
  • if you count things, it's nicer to have them as numbers instead of strings (so you could maybe get rid of the parseInt I used)

1 Comment

I need hierarchy from nth level as i mentioned in the question. if 1 is the parent of 2 and 2 is the parent of 3 so for a count of 1 it will be 2 i am not counting self.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.