1

I'm currently trying to sort a objects properties bases on a value of the properties properties if that makes sense.

var obj = { 
    1: { name: "Mike", surname: "Smith"},
    2: { name: "Albert", surname: "Einstein"},
    3: { name: "Steve", surname: "Jobs"}
}

Say I want to sort the order of these properties by surname so the end result is

var obj = { 
    2: { name: "Albert", surname: "Einstein"},
    3: { name: "Steve", surname: "Jobs"},
    1: { name: "Mike", surname: "Smith"}
}

Surely there has to be an elegant way of doing this other than putting all the surnames into an array sorting that and then reconstructing the object.

jean-max
  • 1,640
  • 1
  • 18
  • 33
Ernie
  • 567
  • 2
  • 6
  • 23

2 Answers2

4

Please try this code:

var arr = [
    {
        f_name: 'George',
        l_name: 'Washington',
        age: 279
    },
    {
        f_name: 'Abraham',
        l_name: 'Lincoln',
        age: 202
    },
    {
        f_name: 'Barack',
        l_name: 'Obama',
        age: 50
    }
];

$(function() {
    $('#headings th').click(function() {
        var id = $(this).attr('id');
        var asc = (!$(this).attr('asc')); // switch the order, true if not set
        
        // set asc="asc" when sorted in ascending order
        $('#headings th').each(function() {
            $(this).removeAttr('asc');
        });
        if (asc) $(this).attr('asc', 'asc');
        
        sortResults(id, asc);
    });
        
    showResults();
});

function sortResults(prop, asc) {
    arr = arr.sort(function(a, b) {
        if (asc) return (a[prop] > b[prop]);
        else return (b[prop] > a[prop]);
    });
    showResults();
}

function showResults () {
    var html = '';
    for (var e in arr) {
        html += '<tr>'
            +'<td>'+arr[e].f_name+'</td>'
            +'<td>'+arr[e].l_name+'</td>'
            +'<td>'+arr[e].age+'</td>'
        +'</tr>';
    }
    $('#results').html(html);
}
table {
    margin: 3px;
}
table th {
    font-weight: bold;
    cursor: pointer;
}
table th, table td {
    padding: 3px;
    border: 1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Click on the table headings to sort the results.
<table>
    <thead id="headings">
        <tr>
            <th id="f_name">First Name</th>
            <th id="l_name">Last Name</th>
            <th id="age">Age</th>
        </tr>
    </thead>
    <tbody id="results">
        <!-- this will be auto-populated -->
    </tbody>
</table>
Sarika Koli
  • 773
  • 6
  • 11
  • This code works but still relays on the original variable being a array, Im actually using angularJS and trying to use ng-repeat on this object and I know it only works with arrays. – Ernie Dec 29 '16 at 11:06
1

What you need is an object that has an order. That could be an Array or Map.

You then need to think about your data schema (i.e. the shape of the JSON data emitted from the server). I might move the ID into the objects themselves (the alternative is to make it implicit, which is brittle and error-prone).

[
  {
    "id": 1,
    "name": "Fred", 
    ...
  }
]

At that point it is just a sorting problem.

Array has a sort function on the prototype.

Note if you need to perform a conversion to an array, you can use Array.from:

var obj = { 
  1: { name: "Mike", surname: "Smith" },
  2: { name: "Albert", surname: "Einstein" },
  3: { name: "Steve", surname: "Jobs" },
  length: 4 // largest *zero-based* index 
};

console.log(Array.from(obj));

The resulting array will be sparse (have gaps) so you will then need to filter the result to eliminate them:

Array.from(obj).filter(populated);

function populated(v) {
  return !!v;
}
Ben Aston
  • 53,718
  • 65
  • 205
  • 331
  • I was afraid this is the only way, but I think I can make it work. An copy of this gets used by ng-repeat and only there so I guess changing the map to an array of maps for that is not the end of the world. – Ernie Dec 29 '16 at 11:09