简体   繁体   中英

JavaScript objects sorting

Ive got an array of objects, something like this:

tab = [
{ top: true, i: 2, bottom: false },
{ top: true, i: 5, bottom: false },
{ top: true, i: 6, bottom: false },
{ top: false, i: 1, bottom: false },
{ top: false, i: 8, bottom: false },
{ top: false, i: 1, bottom: false },
{ top: false, i: 2, bottom: true },
{ top: false, i: 3, bottom: true },
{ top: false, i: 1, bottom: true },
{ top: true, i: 5, bottom: false }
]

And I want to sort it, lets say we have object A and B:

  1. if top == true, put it at the top of the list
  2. if Ai == Bi, put A and B next to each other no matter what
  3. if bottom == true, put it at the end of list

So the array from above, sorted would look something like this:

{ top: true, i: 2, bottom: false },
{ top: false, i: 2, bottom: true },
{ top: true, i: 5, bottom: false },
{ top: true, i: 5, bottom: false },
{ top: true, i: 6, bottom: false },
{ top: false, i: 8, bottom: false },
{ top: false, i: 1, bottom: false },
{ top: false, i: 1, bottom: false },
{ top: false, i: 1, bottom: true },
{ top: false, i: 3, bottom: true }

Im using Array.sort, but I cant make it work and it drives me crazy, any idea?

EDIT: I see that the rules arent clear enough, so Ill try to be more specify now:

  1. if Ai == Bi, put A and B next to each other no matter what
  2. if top == true, put it at the top of the list
  3. if bottom == true, put it at the end of list

  4. A.top: true, A.bottom: true - impossible case

  5. A.top: true, B.top: true, Ai != Bi - order doesnt matter, same with bottom
  6. top has higher priority then botttom, so if A.top: true, B.bottom: true, Ai = Bi then we put them at the top

You can use JavaScript's built in sort method for arrays. It accepts a callback, which can be used to compare the items to determine the sort order. The callback is called with pairs of items from the array. If the first argument provided to the callback is to appear first, return a negative number, if it doesn't matter return 0, and if the second is to appear first return a positive number. In your case, the call would look something like this:

 var tab = [ { top: true, i: 2, bottom: false }, { top: true, i: 5, bottom: false }, { top: true, i: 6, bottom: false }, { top: false, i: 1, bottom: false }, { top: false, i: 8, bottom: false }, { top: false, i: 1, bottom: false }, { top: false, i: 2, bottom: true }, { top: false, i: 3, bottom: true }, { top: false, i: 1, bottom: true }, { top: true, i: 5, bottom: false } ]; var hasTop = {}; var hasBottom = {}; tab.forEach(function (t) { if (t.top) { hasTop[ti] = true; } if (t.bottom) { hasBottom[ti] = true; } }); tab.sort(function (a, b) { if (hasTop[ai] && hasTop[bi]) { return ai - bi; } else if (hasTop[ai] && !hasTop[bi]) { return -1; } else if (!hasTop[ai] && hasTop[bi]) { return 1; } else if (hasBottom[ai] && hasBottom[bi]) { return ai - bi; } else if (hasBottom[ai] && !hasBottom[bi]) { return 1; } else if (!hasBottom[ai] && hasBottom[bi]) { return -1; } else { return 0; } }); document.getElementById("foo").innerText = JSON.stringify(tab, null, 4); 
 #foo { white-space: pre; } 
 <div id="foo"> </div> 

Also, be aware that the sort built-in sorts the array in place instead of creating a new sorted array.

EDIT:

In the original reply, I misunderstood the description of the rules, but after the update and more careful consideration I have figured out the problem. The sort order depends not just on the local properties of the two items, but whether any item with the same index ( i property) has a top or bottom property which is true, a global property of the array. In order to handle this, you must make a pass through the data and record if there is any item with a top or bottom property which is true with the given index. There may be a clever way to do this while inside the sort callback, but I did not see one. Also, note that my original post got the sign of the return value of the sort callback wrong. It has been corrected in this edit.

This is a proposal with a single sort and an object for sort order. It uses a value as default value of 1e6 , big enough to be greater than the value of i . If not assigned, it uses the half value of it.

 var tab = [{ top: true, i: 2, bottom: false }, { top: true, i: 5, bottom: false }, { top: true, i: 6, bottom: false }, { top: false, i: 1, bottom: false }, { top: false, i: 8, bottom: false }, { top: false, i: 1, bottom: false }, { top: false, i: 2, bottom: true }, { top: false, i: 3, bottom: true }, { top: false, i: 1, bottom: true }, { top: true, i: 5, bottom: false }], object = { top: {}, bottom: {} }; tab.forEach(function (t) { object.top[ti] = object.top[ti] || 0.5e6; object.bottom[ti] = object.bottom[ti] || 0.5e6; if (t.top) { object.top[ti] = ti; } if (t.bottom) { object.bottom[ti] = 1e6 + ti; } }); tab.sort(function (a, b) { return object.top[ai] - object.top[bi] || object.bottom[ai] - object.bottom[bi]; }); console.log(tab); 

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