3

I have a large array of objects (1500+) and the objects match on one of the properties. So the overall number of objects could be reduced e.g. for better performance in ng-repeat. I'm kind of new to AngularJS and JS itself, so help is much appreciated!

my Array of Objects (simplified)

myArray = [
    {
        "role": "user111",
        "operation": "create",
        "concept": "folder"
    },
    {
        "role": "user111",
        "operation": "create",
        "concept": "task"
    },
    {
        "role": "user111",
        "operation": "delete",
        "concept": "task"
    },
    {
        "role": "user222",
        "operation": "create",
        "concept": "folder"
    },
    {
        "role": "user222",
        "operation": "create",
        "concept": "task"
    },
    {
        "role": "user222",
        "operation": "delete",
        "concept": "task"
    }
]

desired Output

dreamArray = [
    {
        "role": "user111",
        "operation": {
               "create": ["folder", "task"],
               "delete": ["task"]
                      }
    },
    {
        "role": "user222",
        "operation": {
                   "create": ["folder", "task"],
                   "delete": ["task"]
                      }
    }
]
3
  • 1
    Do you always receive your object sorted on the role property like in your example data? If so that's a valuable information and can greatly simplify the code. Commented Jun 7, 2017 at 15:50
  • @Redu in fact I do! How would this simplify things? Commented Jun 10, 2017 at 20:16
  • Well then you can do this just in O(n) time by using a single .reduce() operation. See my answer below. Commented Jun 11, 2017 at 15:54

4 Answers 4

3

You can do this using forEach() loop and thisArg parameter.

var myArray = [{"role":"user111","operation":"create","concept":"folder"},{"role":"user111","operation":"create","concept":"task"},{"role":"user111","operation":"delete","concept":"task"},{"role":"user222","operation":"create","concept":"folder"},{"role":"user222","operation":"create","concept":"task"},{"role":"user222","operation":"delete","concept":"task"}]

var result = [];
myArray.forEach(function(e) {
  if(!this[e.role]) {
   this[e.role] = {role: e.role, operation: {[e.operation]: [e.concept]}}
    result.push(this[e.role]);
  } else {
    var op = this[e.role].operation[e.operation]
    if(op) op.push(e.concept)
    else this[e.role].operation[e.operation] = [e.concept]
  }
}, Object.create(null))


console.log(result)

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

Comments

3

You could use a hash table and store the reference to the groups.

var array = [{ role: "user111", operation: "create", concept: "folder" }, { role: "user111", operation: "create", concept: "task" }, { role: "user111", operation: "delete", concept: "task" }, { role: "user222", operation: "create", concept: "folder" }, { role: "user222", operation: "create", concept: "task" }, { role: "user222", operation: "delete", concept: "task" }],
    grouped = array.reduce(function (hash) {
        return function (r, o) {
            if (!hash[o.role]) {
                hash[o.role] = {};
                r.push({ role: o.role, operation: hash[o.role]});
            }
            hash[o.role][o.operation] = hash[o.role][o.operation] || [];
            hash[o.role][o.operation].push(o.concept);
            return r;
        };
    }(Object.create(null)), []);

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Comments

1

Using reduce() and find()

var myArray = [{ role: "user111", operation: "create", concept: "folder" }, { role: "user111", operation: "create", concept: "task" }, { role: "user111", operation: "delete", concept: "task" }, { role: "user222", operation: "create", concept: "folder" }, { role: "user222", operation: "create", concept: "task" }, { role: "user222", operation: "delete", concept: "task" }],

const dreamArray = myArray.reduce((acc, item) => {
    let obj = acc.find(e => e.role === item.role);
  if(!obj){
    obj = {"role" : item.role, "operation": {[item.operation]: [item.concept]}};
    acc.push(obj);
  }else{
    obj.operation[item.operation] = obj.operation[item.operation] || [];
    obj.operation[item.operation].push(item.concept);
  }
  return acc;
}, []);

console.log(dreamArray);

Comments

0

As I have mentioned in my comment, if you happen to receive the data already sorted on the role property (which you say so) then the required operation boils down to a very simple .reduce() operation and can be implemented with O(n) time complexity as follows;

var data   = [{"role":"user111","operation":"create","concept":"folder"},{"role":"user111","operation":"create","concept":"task"},{"role":"user111","operation":"delete","concept":"task"},{"role":"user222","operation":"create","concept":"folder"},{"role":"user222","operation":"create","concept":"task"},{"role":"user222","operation":"delete","concept":"task"}],
    result = data.reduce((r,c,i) => !i || r[r.length-1].role !== c.role ? r.concat({"role": c.role, "operation": c.operation === "create" ? {"create": [c.concept], "delete": []}
                                                                                                                                          : {"create": [], "delete": [c.concept]}})
                                                                        : r[r.length-1].operation[c.operation].includes(e => e === c.concept) ? r
                                                                                                                                              :(r[r.length-1].operation[c.operation].push(c.concept),r), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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.