2

I have an array of objects, and I'm trying to group and display them like so:

Level A: BobM, MollyF

Level B: SueF, JoeN, JackF

Here's the jsFiddle: http://jsfiddle.net/PtNLL/4/

var list ={"PEOPLE": [
    {  "name": "Bob",   "level": "A",  "gender": "F"},
    {  "name": "Sue", "level": "B", "gender": "F"},
    {  "name": "Molly", "level": "A", "gender": "M"},
    {  "name": "Joe",  "level": "B", "gender": "N"},
    {  "name": "Jack", "level": "B",  "gender": "F"}
]};


var lvlList = new Array();

for(var i in list.PEOPLE){
     var key = list.PEOPLE[i].level;
    lvlList[key].push(list.PEOPLE[i]);
}

$('#dir2').append( "Here are the Level As");
for(var j in lvlList["A"]) { 
    $('#dir2').append( lvlList[j].name +lvlList[j].gender + "<br/>");
}

$('#dir2').append( "Here are the Level Bs");
for(var k in lvlList["B"]) { 
    $('#dir2').append( lvlList[k].name + lvlList[k].gender +  "<br/>");
}

Also, I am aware there is a group function for underscore, but I don't understand it and I could not get it working: http://jsfiddle.net/5J553/1/ if anyone thinks that is a better method.

4
  • 1
    jsFiddle is nice and helpful in that it saves us (SO users) from having to cut and paste your code, however, it's not a substitute for putting your code here. Some of us can't get to jsFiddle while we're in work, so your question makes no real sense. Commented Jun 13, 2014 at 18:29
  • Thanks for the heads up. I edited my code into the post. Commented Jun 13, 2014 at 19:42
  • @eternal Did you get any helpful answer yet? Commented Jun 17, 2014 at 10:26
  • @Qwerty Yes. All of the answers work just fine for what I was looking for. However, I marked yours as the answer for solving the specific problem I had. Commented Jun 17, 2014 at 15:39

5 Answers 5

2

I wasn't able to run your code as you cannot push an item to a non array. I made it work using this:

var lvlList = [];

for(var i in list.PEOPLE){
    var key = list.PEOPLE[i].level;
    (key in lvlList) ? lvlList[key].push(list.PEOPLE[i]) : lvlList[key] = [list.PEOPLE[i],];
}


for (var key in lvlList.A) {
    console.log(lvlList.A[key].name, lvlList.A[key].gender);
}

for (var key in lvlList["B"]) {
    console.log(lvlList["B"][key].name, lvlList["B"][key].gender);
}

Now just substract the console.log for your jQuery.append and you are ready to go.

EDIT

Note that this "Array" will behave differently from ordinary arrays. To print it's members you can't simply write the name.. the array is empty. Nor you can use .forEach(). This screenshot is taken from Chrome console. (I like Chrome for console scripting the most.)

Chrome console

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

7 Comments

The reason the OPs push isn't working is because he is trying to push an element to the second dimension of a one dimensional array.
+1 I had a feeling it was that, but I was having trouble visualizing it. Thanks for the solution and for demonstrating different syntax of using the lvlList array.
I didn't know you can do that with vanilla JS arrays with non-numeric 'indices' ---- lvlList[key]..., lvlList being var lvlList = [] and key being 'A' or 'B' .. do you have a working demo?
@user3558931 It's not exactly an Associative Array (you can't iterate over those with .forEach()), but rather an array with "some" attributes. Look: lvlList.someFunction = function(){console.log("legit")} then lvlList.someFunction(); // prints "legit". Cool, right? :)
@eternal It's normal to have problems visualising these things, I myself had, haha, that's why I substituted the jQuery with console.log :). Also I've made an edit, see the screenshot attached.
|
2

First... the way you call push() is wrong. It should be called like this : array.push(x)

You should look into using a struct in Javascript. That is truly the best part of this, is that it doesn't require jQuery

Function for creating a struct :

function makeStruct(names) {
  var names = names.split(' ');
  var count = names.length;
  function constructor() {
    for (var i = 0; i < count; i++) {
      this[names[i]] = arguments[i];
    }
  }
  return constructor;
}

Now, you have to create an instance of the structure...

var Person = makeStruct("name level gender");

Then you need to add people to your structure...

var people = [
                new Person('Bob', 'A', 'M'),
                new Person('Sue', 'B', 'F'),
                new Person('Molly', 'A', 'F'),
                new Person('Joe', 'B', 'N'),
                new Person('Jack', 'B', 'M')
             ];

Now to access just use a simple loop :

var i;
for(i = 0; i < people.length; i++){
    //access the elements of the struct -- Put your conditionals as needed
    console.log("Name : " + people[i].name + "; Level : " + people[i].level + "; Gender : " + people[i].gender);
}

As simple as that, just in the for loop you can put your conditionals... If people[i].level == "B" put in list B... etc.

2 Comments

This certainly looks cleaner than using object literals. I'll look into it. Is it a lot better performance-wise?
@eternal I have never used your method before, so I can't say without certainty, but I have never had a performance issue when using this. If I had to guess though, I would say creating the array this way is slower (but negligible), because you are creating new objects inside the array with a constructor. Personally, I come from a programming background in C, so using this in JS is incredibly awesome and extremely versatile, not to mention much cleaner. So long as you have the makeStruct function you can create structs all day.
1

Your code is fine. You need to add jQuery reference in your second jsFiddle.

var grp = _.groupBy(list.PEOPLE, function (person) {
    return person.level;
});

Here is a working example.

1 Comment

Thanks- I did for get to add underscore.js to the external resources.
1

In your first demo you declared lvlList as an array but in it's usage you used it as both an array and an object; it should be declared as an object and used as such -- see my code and demo. I group the objects using JavaScript and display using jQuery.

You can use the JavaScript filter() array method like so:

var lvlList = {};
lvlList.A = list.PEOPLE.filter(function(obj) { return obj.level == 'A'; });
lvlList.B = list.PEOPLE.filter(function(obj) { return obj.level == 'B'; });

$('#dir2').append( "Here are the Level As<br>");
$.each(lvlList["A"],function(i,v) { 
    $('#dir2').append( v.name + v.gender + "<br/>");
});

$('#dir2').append( "Here are the Level Bs<br/>");
$.each(lvlList["B"], function(i,v) { 
    $('#dir2').append( v.name + v.gender +  "<br/>");
});

WORKING JS FIDDLE DEMO

Result

Here are the Level As 
BobF 
MollyM 
Here are the Level Bs 
SueF 
JoeN
JackF

4 Comments

Thank you. I considered using filter() to filter each level, but I heard that it is slower than a one loop. What do you think?
That's a very valid consideration for a site where performance is key. Once I return from my weekend out, I'll put together some simple tests and I'll be sure to share them with you, if you're interested. So you said .filter() vs forEach(), right?
It would be many .filter() versus one forEach()? I think I'm going to go with _.groupBy(), and then Qwerty' solution of fixing the array using the forEach(). Don't run the tests for me, but feel free to share them with me if you do find something!
Sure, you've got it. The pleasure was all mine. Ciao!!
0

You can create two divs and append then like this:

  $.each(list.PEOPLE,function(index,item){
    if(item.level === "A")
        $("#levelA").append(item.name+"<br/>")
    if(item.level === "B")
        $("#levelB").append(item.name+"<br/>");
})

FIDDLE DEMO

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.