简体   繁体   中英

How to split array of objects up based on parameter, sort only one, then join again in Lodash

Let's say I have an array of objects like:

var posts = [{
  queued: false,
  score: 3
}, {
  queued: false,
  score: 2
}, {
  queued: false,
  score: 1
}, {
  queued: 100,
  score: 0
}, {
  queued: 56,
  score: 1
}]

I want to split up based on the queued property, one array has all the queued: false , the other has everything else. I then want to sort by score and join them.

I can do the following:

let queuedPosts = _.filter(posts, function(post) {
  return post.queued !== false;
});
let unqueuedPosts = _.filter(posts, function(post) {
  return post.queued === false;
});

Then sort queuedPosts by its property queued , then unqueuedPosts by score , and posts = _.concat(queuedPosts, unqueuedPosts) . This would not be scalable if I were to split by some other property in the future. What would be a cleaner way to do this?

EDIT: Code currently looks like this

 sortPosts(posts) {
    let queuedPosts = _.filter(posts, (post) => (post.queued !== false));
    let unqueuedPosts = _.difference(posts, queuedPosts);
    queuedPosts = orderBy(queuedPosts, 'queued', 'asc');
    unqueuedPosts = orderBy(unqueuedPosts, 'score', 'desc');
    return [...queuedPosts, ...unqueuedPosts];
  }

I believe if I make use of the _.remove method, I can programmatically use another object containing keys, sort order, and limits, I can modify this to dynamically sort depending on user's needs via an input like some checkboxes.

I would just use a single .sort() operation to do everything in one step. You don't need to split the array up first.

I found your wording a little confusing, but my interpretation of the desired result is as follows:

  • Non-false queued items to appear first, sorted by queued then score
  • queued: false items to appear last, sorted by score

 var posts = [ { queued: false, score: 3 }, { queued: false, score: 2 }, { queued: 100, score: 10 }, { queued: false, score: 1 }, { queued: 100, score: 0 }, { queued: 56, score: 1 } ] var sorted = posts.slice().sort(function(a,b) { return a.queued === b.queued ? a.score - b.score : !a.queued ? 1 : !b.queued ? -1 : a.queued - b.queued }) console.log(sorted) 

To make it more scalable you can simply use a separate filter function like this:

function filter(post) {
   return post.queued !== false;
}

Then call the lodash filter function like:

let queuedPosts = _.filter(posts,filter);
//Use lodash difference to find unqueued posts
let unqueuedPosts = _.difference(posts, queuedPosts);

You can also use _.remove to get two separate arrays like:

let queuedPosts = _.remove(posts,filter);
//posts now has all the unqueued objects.

Edit

To sort and concat you can simply use following single line code to get the desired results (without separating the array)

Edit 2

Allow negative queued values.

 const posts = [{ queued: false, score: 3 }, { queued: false, score: 2 }, { queued: false, score: 1 }, { queued: 100, score: 0 }, { queued: 56, score: 1 }, { queued: -3, //Negative queue value score: 2 }]; //best possible answer to the problem. const sortedPosts = _.orderBy(posts,[(p)=>[p.queued!==false,p.queued===false]],['desc','desc']); console.log(sortedPosts); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script> 

Just sort the elements, using the appropriate sort function.

 var posts = [ {queued: false, score: 3}, {queued: false, score: 2}, {queued: false, score: 1}, {queued: 100, score: 0}, {queued: 56, score: 1} ]; posts.sort((p1, p2) => { const q1 = Boolean(p1.queued), q2 = Boolean(p2.queued); return q1 === q2 ? p1.score - p2.score : // sort by ascending score within group q2 - q1; // sort non-false `queue` values first }); console.log(posts); 

Using lodash:

 var posts = [ {queued: false, score: 3}, {queued: false, score: 2}, {queued: false, score: 1}, {queued: 100, score: 0}, {queued: 56, score: 1} ]; console.log(_.sortBy(posts, [p => !Boolean(p.queued), 'score'])); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script> 

If splitting up is your main worry, you might want to look at the lodash partition function:

const [queuedPosts, unqueuedPosts] = _.partition(posts, 'queued');

Of course you can replace 'queued' by any other predicate.

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