0

I have a JSON array like this

[{"Email":"[email protected]","Name":"ACO","Groups":["MOD_SW","MOD_PI","MOD_GE"],"Id":63,"Url":"aco"},
{"Email":"[email protected]","Name":"Agpo","Groups":["MOD_PI"],"Id":22,"Url":"agpo"},
{"Email":"[email protected]","Name":"Akatherm","Groups":["MOD_SW"],"Id":64,"Url":"akatherm"},
{"Email":"[email protected]","Name":"Albrand","Groups":["MOD_PI,"MOD_GE"],"Id":23,"Url":"albrand"}]

I want to create a new array (for select tag) with distinct Groups.

This Groups is an array.

I want that selectbox to have the following values:

MOD_SW
MOD_PI
MOD_GE

My JS:

UpdateSelectMenu: function (selectId, data) {
      $(selectId).empty();
      $(selectId).html("<option value='all' selected='selected'>All groups</option>");
      var array_unique_values = [];

      for (var i = 0; i < data.Groups.length; i++) {
         for (var j = i+1; j < data.Groups.length; j++) {
            if (data.Groups[i] === data.Groups[j]) {
               j = ++i;
            }
         }
         array_unique_values.push(data.Groups[i]);
      }

      array_unique_values = array_unique_values.sort();

      $.each(array_unique_values, function (k, v) {
         $(selectId).append("<option value='" + v + "'>" + v + "</option>");
      });
   }

I tried also

for (var i = 0; i < data.length; i++) {  //browse whole data
         for (var j = 0; j < data[i].Groups.length; j++) {  //browse Groups array
            for (var k = j + 1; j < data[i].Groups.length; k++) {
               if (data[i].Groups[j] === data[i].Groups[k]) {
                  continue;
               }
            }

            array_unique_values.push(data[i].Groups[j]);
         }
      }

But error appears as: Groups.length is null or not an object

This code appends to select tag the Group values but it appears as duplicates because Groups is an array.

I have to create a new for statement to browse the Groups array ?

Or there is another alternative to avoid nested for statements ?

Thank you

2 Answers 2

3

2 nested loops could do the job:

var data = [... your data ...];
var groups = [];
$.each(data, function(i, item) {
    $.each(item.Groups, function(j, group) {
        if ($.inArray(group, groups) == -1) {
            groups.push(group);
        }
    });    
});

// at this stage groups = ["MOD_SW", "MOD_PI", "MOD_GE"]

and if you wanted to directly append options to your dropdown:

var groups = [];
$.each(data, function(i, item) {
    $.each(item.Groups, function(j, group) {
        if ($.inArray(group, groups) == -1) {
            groups.push(group);
            $(selectId).append(
                $('<option/>', {
                    value: group,
                    text: group
                })
            );
        }
    });    
});

UPDATE:

And to make this more efficient you could define a static dtstinct method:

$.extend({
    distinct : function(arr) {
       var result = [];
       $.each(arr, function(index, value) {
           if ($.inArray(value, result) == -1) {
               result.push(value);
           }
       });
       return result;
    }
});

and then use the .map method:

var data = [... your data ...];
var groups = $.distinct($(data).map(function() {
    return this.Groups;    
}));
$.each(groups, function(index, group) {
    $(selectId).append(
        $('<option/>', {
            value: group,
            text: group
        })
    );
});
Sign up to request clarification or add additional context in comments.

3 Comments

$.inArray is making a loop (if indexOf is unavailable) and I think that's quite inefficient.
all respect for you Darin :) You saved my life. These $.each didn't passed through my brain.
@mgechev, good point. I have updated my answer with an alternative which is more efficient.
2

First look at the last group: "Groups":["MOD_PI,MOD_GE"] Don't you need to close the quotes after MOD_PI and open them after the comma or this is a set of groups?

If this with the quotes is problem the your script can look something like this:

var obj = [{"Email":"[email protected]","Name":"ACO", "Groups":["MOD_SW","MOD_PI","MOD_GE"],"Id":63,"Url":"aco"},
{"Email":"[email protected]","Name":"Agpo", "Groups":["MOD_PI"],"Id":22,"Url":"agpo"},
{"Email":"[email protected]","Name":"Akatherm", "Groups":["MOD_SW"],"Id":64,"Url":"akatherm"},
{"Email":"[email protected]","Name":"Albrand", "Groups":["MOD_PI","MOD_GE"],"Id":23,"Url":"albrand"}]

var temp = {}, 
    result = [];

for (var i = 0; i < obj.length; i+=1) {
    for (var j = 0; j < obj[i]['Groups'].length; j+=1) {
        if (typeof temp[obj[i]['Groups'][j]] === 'undefined') {
            result.push(obj[i]['Groups'][j]);
            temp[obj[i]['Groups'][j]] = true;
        }
    }
}

If this is a set of groups:

for (var i = 0; i < obj.length; i+=1) {
    for (var j = 0; j < obj[i]['Groups'].length; j+=1) {
        currentGroups = obj[i]['Groups'][j].split(',');
        for (var k = 0; k < currentGroups.length; k += 1) {
            currentGroups[k] = currentGroups[k].replace(/ /g,"");
            if (typeof temp[currentGroups[k]] === 'undefined') {
                result.push(currentGroups[k]);
                temp[currentGroups[k]] = true;
            }       
        }
    }
}

I think that's the most efficient way because you're checking for duplicates with O(1) and you don't have to do extra work (for example sort any array).

1 Comment

You're welcome. I've posted version where you can check even for a set of groups. I think that this is going to help you in both cases. Greetings!

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.