简体   繁体   中英

Sort an array by a preferred order

I'd like to come up with a good way to have a "suggested" order for how to sort an array in javascript.

So say my first array looks something like this:

['bob','david','steve','darrel','jim']

Now all I care about, is that the sorted results starts out in this order:

['jim','steve','david']

After that, I Want the remaining values to be presented in their original order.

So I would expect the result to be:

['jim','steve','david','bob','darrel']

I have an API that I am communicating with, and I want to present the results important to me in the list at the top. After that, I'd prefer they are just returned in their original order.

If this can be easily accomplished with a javascript framework like jQuery, I'd like to hear about that too. Thanks!

Edit for clarity:

I'd like to assume that the values provided in the array that I want to sort are not guaranteed.

So in the original example, if the provided was:

['bob','steve','darrel','jim']

And I wanted to sort it by:

['jim','steve','david']

Since 'david' isn't in the provided array, I'd like the result to exclude it.

Edit2 for more clarity: A practical example of what I'm trying to accomplish:

The API will return something looking like:

['Load Average','Memory Usage','Disk Space']

I'd like to present the user with the most important results first, but each of these fields may not always be returned. So I'd like the most important (as determined by the user in some other code), to be displayed first if they are available.

Something like this should work:

var presetOrder = ['jim','steve','david']; // needn't be hardcoded

function sortSpecial(arr) {
   var result = [],
       i, j;
   for (i = 0; i < presetOrder.length; i++)
      while (-1 != (j = $.inArray(presetOrder[i], arr)))
         result.push(arr.splice(j, 1)[0]);
   return result.concat(arr);
}

var sorted = sortSpecial( ['bob','david','steve','darrel','jim'] );

I've allowed for the "special" values appearing more than once in the array being processed, and assumed that duplicates should be kept as long as they're shuffled up to the front in the order defined in presetOrder .

Note: I've used jQuery's $.inArray() rather than Array.indexOf() only because that latter isn't supported by IE until IE9 and you've tagged your question with "jQuery". You could of course use .indexOf() if you don't care about old IE, or if you use a shim .

var important_results = {
  // object keys are the important results, values is their order
  jim: 1,
  steve: 2,
  david: 3
  };

// results is the orig array from the api
results.sort(function(a,b) {
    // If compareFunction(a, b) is less than 0, sort a to a lower index than b.
    // See https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort
    var important_a = important_results[a], 
        important_b = important_results[b],
        ret;

    if (important_a && !important_b) {ret = -1}
    else if (important_b && !important_a) {ret = 1}
    else if (important_a && important_b) {ret = important_a - important_b}
    else {ret = 0}; // keep original order if neither a or b is important

    return(ret);
  }
)

Use a sorting function that treats the previously known important results specially--sorts them to the head of the results if present in results.

  • items in important_results don't have to be in the results

Here's a simple test page:

<html>
<head>
<script language="javascript">
function test()
{
   var items = ['bob', 'david', 'steve', 'darrel', 'jim'];
   
   items.sort(function(a,b)
        {
           var map = {'jim':-3,'steve':-2,'david':-1};
           return map[a] - map[b];
         });
    alert(items.join(','));
}
</script>
</head>
<body>
<button onclick="javascript:test()">Click Me</button>
</body>
</html>

It works in most browsers because javascript typically uses what is called a stable sort algorithm , the defining feature of which is that it preserves the original order of equivalent items. However, I know there have been exceptions. You guarantee stability by using the array index of each remaining item as it's a1/b1 value.

there can be another way of sorting on order base, also values can be objects to work with

const inputs = ["bob", "david", "steve", "darrel", "jim"].map((val) => ({
  val,
}));
const order = ["jim", "steve", "david"];

const vMap = new Map(inputs.map((v) => [v.val, v]));
const sorted = [];
order.forEach((o) => {
  if (vMap.has(o)) {
    sorted.push(vMap.get(o));
    vMap.delete(o);
  }
});
const result = sorted.concat(Array.from(vMap.values()));
const plainResult = result.map(({ val }) => val);

http://tinysort.sjeiti.com/

I think this might help. The $('#yrDiv').tsort({place:'start'}); will add your important list in the start.

You can also sort using this function the way you like.

Live demo ( jsfiddle seems to be down)

http://jsbin.com/eteniz/edit#javascript,html

var priorities=['jim','steve','david'];

var liveData=['bob','david','steve','darrel','jim'];


var output=[],temp=[];  
for ( i=0; i<liveData.length; i++){
    if( $.inArray( liveData[i], priorities) ==-1){
        output.push( liveData[i]);
    }else{
        temp.push( liveData[i]);
    }
}
var temp2=$.grep( priorities, function(name,i){
        return $.inArray( name, temp) >-1;                             
});

output=$.merge( temp2, output);

Have you considered using Underscore.js ? It contains several utilities for manipulating lists like this.

In your case, you could:

  1. Filter the results you want using filter() and store them in a collection.

    var priorities = _.filter(['bob','david','steve','darrel','jim'], function(pName){ if (pName == 'jim' || pName == 'steve' || pName == 'david') return true; });

  2. Get a copy of the other results using without()

    var leftovers = _.without(['bob','david','steve','darrel','jim'], 'jim', 'steve', 'david');

  3. Union the arrays from the previous steps using union()

    var finalList = _.union(priorities, leftovers);

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