简体   繁体   中英

Javascript sort array of objects using nested attributes where some attributes are undefined

I'm trying to implement a sorting function that takes in an array of objects and sorts them by an attribute or a nested attribute. I've looked at a ton of questions on here with good answers to this problem, but so far as I have seen, none of them account for when a nested attribute is missing.

For example, if I sort by some_attribute and some_attribute = undefined for one of my array elements, the element in question is bumped to the end/beginning of the array, as I would expect. If I sort by some_attribute.something_else , the functions I've seen don't respond well when some_attribute.something_else = undefined .

Here is a sample of my data structure I'm trying to sort:

results = [
    {
        id: 233,
        post: "Test 944 AM http://frmply.co/1mA9G3L",
        twitter_favorite_count: 0,
        twitter_retweet_count: 2,
        twitter_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 3
        },
        twitter_last_updated: "2015-12-28T21:11:27.425Z",
        facebook_like_count: null,
        facebook_share_count: 1,
        facebook_comment_count: null,
        facebook_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 1
        },
        facebook_last_updated: "2015-12-28T21:11:29.232Z",
        linkedin_like_count: null,
        linkedin_comment_count: null,
        linkedin_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 0
        },
        linkedin_last_updated: "2015-12-28T21:11:29.905Z"
    },
    {
        id: 232,
        post: "Test 944 AM http://frmply.co/1mA9G3L",
        twitter_favorite_count: null,
        twitter_retweet_count: null,
        twitter_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 5
        },
        twitter_last_updated: null,
        facebook_like_count: null,
        facebook_share_count: null,
        facebook_comment_count: null,
        facebook_link_click_count: { },
        facebook_last_updated: null,
        linkedin_like_count: null,
        linkedin_comment_count: null,
        linkedin_link_click_count: { },
        linkedin_last_updated: null
    },
    {
        id: 234,
        post: "localhost test 1106am http://frmply.co/1RAYalE",
        twitter_favorite_count: 0,
        twitter_retweet_count: 0,
        twitter_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 2
        },
        twitter_last_updated: "2016-01-06T18:40:21.388Z",
        facebook_like_count: null,
        facebook_share_count: null,
        facebook_comment_count: null,
        facebook_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 0
        },
        facebook_last_updated: "2015-12-29T16:07:39.042Z",
        linkedin_like_count: null,
        linkedin_comment_count: null,
        linkedin_link_click_count: {
            minute: null,
            hour: null,
            day: null,
            week: null,
            month: null,
            total: 0
        },
        linkedin_last_updated: "2015-12-29T16:07:39.489Z"
    },
    {
        id: 231,
        post: "test",
        twitter_favorite_count: null,
        twitter_retweet_count: null,
        twitter_link_click_count: { },
        twitter_last_updated: null,
        facebook_like_count: null,
        facebook_share_count: null,
        facebook_comment_count: null,
        facebook_link_click_count: { },
        facebook_last_updated: null,
        linkedin_like_count: null,
        linkedin_comment_count: null,
        linkedin_link_click_count: { },
        linkedin_last_updated: null
    }
]

Now if I run the code below I get [2, 3, 5, undefined] as a result when I would expect [undefined, 2, 3, 5] .

results.sortBy('twitter_link_click_count.total').map(function(x){return x.twitter_link_click_count.total})

In the snippet above, sortBy is a function from this post , however I've also tried using Underscore's _.sortBy function with identical results.

Working Code

Here is the solution I came up with based off Oleg's answer:

var sortKey = attribute.split('.');
var sortBy = function(results, sortKey) {
    return _.sortBy(results, function(item) {
        if(sortKey.length === 1) {
            return item[sortKey[0]] || 0;
        } else {
            return item[sortKey[0]][sortKey[1]] || 0;
        };
    });
};

The key difference here is that it generates a sortKey array, which can be used an an if/else statement or iterated over. I used an if/else since my sortKey is only ever 1 or 2 layers deep inside my object. I also handled cases where my attribute is null by returning 0 instead of true . Hope this helps someone else.

Please try the following script (used Underscore there):

 results = [ { id: 233, post: "Test 944 AM http://frmply.co/1mA9G3L", twitter_favorite_count: 0, twitter_retweet_count: 2, twitter_link_click_count: { minute: null, hour: null, day: null, week: null, month: null, total: 3 }, twitter_last_updated: "2015-12-28T21:11:27.425Z", facebook_like_count: null, facebook_share_count: 1, facebook_comment_count: null, facebook_link_click_count: { minute: null, hour: null, day: null, week: null, month: null, total: 1 }, facebook_last_updated: "2015-12-28T21:11:29.232Z", linkedin_like_count: null, linkedin_comment_count: null, linkedin_link_click_count: { minute: null, hour: null, day: null, week: null, month: null, total: 0 }, linkedin_last_updated: "2015-12-28T21:11:29.905Z" }, { id: 232, post: "Test 944 AM http://frmply.co/1mA9G3L", twitter_favorite_count: null, twitter_retweet_count: null, twitter_link_click_count: { minute: null, hour: null, day: null, week: null, month: null, total: 5 }, twitter_last_updated: null, facebook_like_count: null, facebook_share_count: null, facebook_comment_count: null, facebook_link_click_count: { }, facebook_last_updated: null, linkedin_like_count: null, linkedin_comment_count: null, linkedin_link_click_count: { }, linkedin_last_updated: null }, { id: 234, post: "localhost test 1106am http://frmply.co/1RAYalE", twitter_favorite_count: 0, twitter_retweet_count: 0, twitter_link_click_count: { minute: null, hour: null, day: null, week: null, month: null, total: 2 }, twitter_last_updated: "2016-01-06T18:40:21.388Z", facebook_like_count: null, facebook_share_count: null, facebook_comment_count: null, facebook_link_click_count: { minute: null, hour: null, day: null, week: null, month: null, total: 0 }, facebook_last_updated: "2015-12-29T16:07:39.042Z", linkedin_like_count: null, linkedin_comment_count: null, linkedin_link_click_count: { minute: null, hour: null, day: null, week: null, month: null, total: 0 }, linkedin_last_updated: "2015-12-29T16:07:39.489Z" }, { id: 231, post: "test", twitter_favorite_count: null, twitter_retweet_count: null, twitter_link_click_count: { }, twitter_last_updated: null, facebook_like_count: null, facebook_share_count: null, facebook_comment_count: null, facebook_link_click_count: { }, facebook_last_updated: null, linkedin_like_count: null, linkedin_comment_count: null, linkedin_link_click_count: { }, linkedin_last_updated: null } ]; document.getElementById('output').innerHTML = JSON.stringify(_.sortBy(results, function(item) { return item.twitter_link_click_count.total || true; }).map(function(x){return x.twitter_link_click_count.total})); 
 <script src="http://underscorejs.org/underscore-min.js"></script> <pre id="output"></pre> 

Solution using plain JS filter & map

results = results.filter(function (a) {
    return !!((a.twitter_link_click_count || {}).total)
}).sort(function(a, b){
    return (a.twitter_link_click_count || {}).total > (b.twitter_link_click_count || {}).total
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM