简体   繁体   English

JavaScript“sort()”函数的算法

[英]Algorithm of JavaScript “sort()” Function

Recently when I was working with JavaScript "sort()" function, I found in one of the tutorials that this function does not sort the numbers properly. 最近,当我使用JavaScript“sort()”函数时,我在其中一个教程中发现此函数没有正确排序数字。 Instead to sort numbers, a function must be added that compares numbers, like the following code:- 而不是对数字进行排序,必须添加一个比较数字的函数,如下面的代码:

<script type="text/javascript">
function sortNumber(a,b)
{
    return a - b;
}

var n = ["10", "5", "40", "25", "100", "1"];
document.write(n.sort(sortNumber));
</script>

The output then comes as:- 然后输出如下: -

1,5,10,25,40,100

Now what I didn't understand is that why is this occurring & can anybody please tell in details as to what type of algorithm is being used in this " sort() " function? 现在我不明白的是,为什么会发生这种情况?任何人都可以详细说明这个“ sort() ”函数中使用的算法类型是什么? This is because for any other language, I didn't find this problem where the function didn't sort the numbers correctly. 这是因为对于任何其他语言,我没有发现这个问题,其中函数没有正确排序数字

Any help is greatly appreciated. 任何帮助是极大的赞赏。

To answer your question on how the sorting function works, I will explain it in detail. 要回答关于排序功能如何工作的问题,我将详细解释。 As has been said in most of the answers here, calling only sort() on an array will sort your array using strings. 正如在这里的大多数答案中所说的,在数组上只调用sort()将使用字符串对数组进行排序。 Converting your integers to strings as well. 将整数转换为字符串。 Blech! 布莱什!

If you think of your items as characters instead of numbers it makes sense that it would be sorted that way. 如果您将项目视为字符而不是数字,则可以按照这种方式进行排序。 A good way to see this is to assign letters to your numbers. 看到这个的好方法是为你的数字分配字母。

//0 = a
//1 = b
//2 = c
//4 = e
//5 = f
//These two arrays are treated the same because they're composed of strings.
var nums  = ["10", "5", "40", "25", "100", "1"];
var chars = ["ba", "f", "ea", "cf", "baa", "b"];

//Here we can see that sort() correctly sorted these strings. Looking at the
//alphabetical characters we see that they are in the correct order. Looking
//at our numbers in the same light, it makes sense that they are sorted
//this way as well. After all, we did pass them as strings to our array.
chars.sort(); //["b", "ba", "baa", "cf", "ea", "f"]
nums.sort();  //["1", "10", "100", "25", "40", "5"]

//The bad part of sort() comes in when our array is actually made up of numbers.
var nums = [10, 5, 40, 25, 100, 1];
nums.sort(); //[1, 10, 100, 25, 40, 5]

//As a result of the default sorting function converting numbers to strings 
//before sorting, we get an unwanted result. We can fix this by passing in our 
//own function as a parameter to sort().

You can control how to sort the array by passing your own function as a parameter to the sort() function. 您可以通过将自己的函数作为参数传递给sort()函数来控制如何对数组进行sort() This is nice, but unless you know how the sort() function works, it really won't do you any good. 这很好,但除非你知道sort()函数是如何工作的,否则它对你没有任何帮助。

sort() will call your function multiple times to re-arrange the array. sort()将多次调用您的函数来重新排列数组。 Depending on what is returned from your function tells sort() what to do with the items in the array. 根据函数返回的内容告诉sort()如何处理数组中的项。 If a negative number or 0 is returned, no re-arranging happens. 如果返回负数或0,则不会重新排列。 If a positive number is returned, the two items switch place. 如果返回正数,则两个项目切换位置。 sort() keeps track of which numbers it has already tested, so it doesn't end up testing numbers again later after it has switched the items around. sort()跟踪它已经测试过的数字,因此它不会在切换项目后再次测试数字。 If sort() re-arranges items, it will move back one position and see if it has tested these two items before. 如果sort()重新排列项目,它将向后移动一个位置,看看它是否已经测试过这两个项目。 If it hasn't it will test them. 如果还没有,它会测试它们。 If it has, it will continue on without running your function on them. 如果有,它将继续运行而不在它们上运行您的功能。

Sorting Numbers 排序数字

Let's take a simple example and I will walk you through it: 让我们举一个简单的例子,我将引导您完成它:

var arr = [50, 90, 1, 10, 2];

arr = arr.sort(function(current, next){
    //My comments get generated from here
    return current - next;
});

//1 : current = 50, next = 90
//  : current - next (50 - 90 = -40)
//  : Negative number means no re-arranging
//  : Array now looks like [50, 90, 1, 10, 2]
//
//2 : current = 90, next = 1
//  : current - next (90 - 1 = 89)
//  : Positive number means sort() will switch these positions in the array
//  : Array now looks like [50, 1, 90, 10, 2]
//
//If sort() didn't backtrack, the next check would be 90 and 10, switch those 
//positions, check 90 and 2, and switch again. Making the final array
//[50, 1, 10, 2, 90], not sorted. But lucky for us, sort() does backtrack.
//
//3 : current = 50, next = 1
//  : current - next (50 - 1 = 49)
//  : Positive number means sort() will switch these positions in the array
//  : Array now looks like [1, 50, 90, 10, 2]
//
//If sort() wasn't smart, it would now check 50 and 90 again. What a waste! 
//But lucky for us again, sort() is smart and knows it already made this 
//check and will continue on.
//
//4 : current = 90, next = 10
//  : current - next (90 - 10 = 80)
//  : Positive number means sort() will switch these positions in the array
//  : Array now looks like [1, 50, 10, 90, 2]
//
//sort() backtracks one position and sees that it has not checked 50 and 10
//
//5 : current = 50, next = 10
//  : current - next (50 - 10 = 40)
//  : Positive number means sort() will switch these positions in the array
//  : Array now looks like [1, 10, 50, 90, 2]
//
//sort() backtracks one position and sees that it has not checked 1 and 10
//
//6 : current = 1, next = 10
//  : current - next (1 - 10 = -9)
//  : Negative number means no re-arranging
//  : Array now looks like [1, 10, 50, 90, 2]
//
//sort() remembers that it already checked 10 and 50 so it skips ahead
//sort() remembers that it already checked 50 and 90 so it skips ahead
//
//7 : current = 90, next = 2
//  : current - next (90 - 2 = 88)
//  : Positive number means sort() will switch these positions in the array
//  : Array now looks like [1, 10, 50, 2, 90]
//
//sort() backtracks one position and sees that it has not checked 50 and 2
//
//8 : current = 50, next = 2
//  : current - next (50 - 2 = 48)
//  : Positive number means sort() will switch these positions in the array
//  : Array now looks like [1, 10, 2, 50, 90]
//
//sort() backtracks one position and sees that it has not checked 10 and 2
//
//9 : current = 10, next = 2
//  : current - next (10 - 2 = 8)
//  : Positive number means sort() will switch these positions in the array
//  : Array now looks like [1, 2, 10, 50, 90]
//
//sort() backtracks one position and sees that it has not checked 1 and 2
//
//10: current = 1, next = 2
//  : current - next (1 - 2 = -1)
//  : Negative number means no re-arranging
//  : Array now looks like [1, 2, 10, 50, 90]
//
//sort() remembers that it already checked 2 and 10 so it skips ahead
//sort() remembers that it already checked 10 and 50 so it skips ahead
//sort() remembers that it already checked 50 and 90 so it skips ahead
//sort() has no more items to check so it returns the final array
//which is [1, 2, 10, 50, 90]

If you wanted the array to be ordered in descending order [90, 50, 10, 2, 1] you can just change the return statement from return current - next; 如果您希望按降序[90, 50, 10, 2, 1] 90,50,10,2,1]对数组进行排序,您只需更改return current - next;的return语句return current - next; to return next - current; return next - current; like so: 像这样:

var arr = [50, 90, 1, 10, 2];

arr = arr.sort(function(current, next){
    //My comments get generated from here
    return next - current;
});

//1 : current = 50, next = 90
//  : next - current (90 - 50 = 40)
//  : Positive number means sort() will switch these positions in the array
//  : Array now looks like [90, 50, 1, 10, 2]
//
//2 : current = 50, next = 1
//  : next - current (1 - 50 = -49)
//  : Negative number means no re-arranging
//  : Array now looks like [90, 50, 1, 10, 2]
//
//etc.

It does not matter if your array is composed of "string numbers" "5" or just numbers 5 when using your own function to sort numbers. 使用自己的函数对数字进行排序时,如果您的数组由“字符串数字” "5"或数字5组成,则无关紧要。 Because when JavaScript is doing math, it treats "string numbers" as numbers. 因为当JavaScript进行数学运算时,它会将“字符串数字”视为数字。 ie "5" - "3" = 2 "5" - "3" = 2

Sorting Strings 排序字符串

When you sort strings, you can compare them using the > and < (greater-than and less-than) operators. 排序字符串时,可以使用>< (大于和小于)运算符对它们进行比较。 The greater-than operator sorts the string by ascending order (AZ, 1-9), and the less-than operator sorts by descending order (ZA, 9-1). 大于运算符按升序(AZ,1-9)对字符串进行排序,小于运算符按降序排序(ZA,9-1)。 Different browsers use different sorting algorithms so when sorting by strings you have to make sure you are returning either 1 or -1, not true or false. 不同的浏览器使用不同的排序算法,因此在按字符串排序时,您必须确保返回1或-1,而不是true或false。

For example, this works in Chrome and FF, but not IE: 例如,这适用于Chrome和FF,但不适用于IE:

var arr = ['banana', 'orange', 'apple', 'grape'];

arr = arr.sort(function(current, next){
    return current > next;
});

The way to make sure your sorting algorithm works in every browser, use the ternary operator. 确保排序算法在每个浏览器中都有效的方法,使用三元运算符。

var arr = ['banana', 'orange', 'apple', 'grape'];

arr = arr.sort(function(current, next){
    return current > next? 1: -1;
});

When changing the way you're sorting (by ascending or descending order), in addition to changing the operators, you could keep the same operator and switch the current and next variables as we did when sorting numbers. 在更改排序方式时(按升序或降序排列),除了更改运算符外,还可以保持相同的运算符并切换currentnext变量,就像排序数字时一样。 Or since we are using the ternary operator, you could switch the 1 and -1 . 或者由于我们使用三元运算符,您可以切换1-1

Sorting Objects 排序对象

Here is a neat trick that I thought I'd add in here. 这是一个巧妙的技巧,我认为我会在这里添加。 You can sort objects if you add them to an array and use their key to compare. 如果将对象添加到数组并使用其键进行比较,则可以对对象进行排序。 Here is an example. 这是一个例子。

var arr = [
    {id: 2, name: 'Paul'},
    {id: 1, name: 'Pete'}
];

//sort numerically
arr = arr.sort(function(current, next){
    return current.id - next.id;
});
//Array now looks like [{id: 1, name: 'Pete'}, {id: 2, name: 'Paul'}]

//sort alphabetically
arr = arr.sort(function(current, next){
    return current.name > next.name? 1: -1;
});
//Array now looks like [{id: 2, name: 'Paul'}, {id: 1, name: 'Pete'}]

Recap 概括

To sort numbers 要排序数字
in ascending order (1, 2, 3...) : function(a, b){return a - b;} 按升序排列(1,2,3 ......)function(a, b){return a - b;}
in descending order (9, 8, 7...) : function(a, b){return b - a;} 降序排列(9,8,7 ......)function(a, b){return b - a;}

To sort strings 排序字符串
in ascending order (A, B, C...) : function(a, b){return a > b? 1: -1;} 按升序排列(A,B,C ......)function(a, b){return a > b? 1: -1;} function(a, b){return a > b? 1: -1;}
in descending order (Z, Y, X...) : function(a, b){return b > a? 1: -1;} 降序排列(Z,Y,X ......)function(a, b){return b > a? 1: -1;} function(a, b){return b > a? 1: -1;}

To sort objects add them to an array, 要对对象排序,请将它们添加到数组中,
then sort by key: function(a, b){return a.key - b.key;} 然后按键排序: function(a, b){return a.key - b.key;}

Well, if you are sorting the following list, it contains only strings: 好吧,如果你要对以下列表进行排序,它只包含字符串:

var n = ["10", "5", "40", "25", "100", "1"];

So I would expect any language would compare them as strings, thus resulting in a sort order of: 所以我希望任何语言都将它们作为字符串进行比较,从而产生以下排序顺序:

var n = ["1", "10", "100", "25", "40", "5"];

Which necessitates your code to use a custom sort (as you have done) to cast the strings back to integers for the purposes of sorting. 这需要您的代码使用自定义排序(如您所做)将字符串强制转换为整数以进行排序。

Edit 编辑

As Pointy mentioned, by default the JavaScript sort() method sorts elements alphabetically, including numbers: 正如Pointy所提到的,默认情况下, JavaScript sort()方法按字母顺序元素进行排序,包括数字:

By default, the sort() method sorts the elements alphabetically and ascending. 默认情况下,sort()方法按字母顺序和升序对元素进行排序。 However, numbers will not be sorted correctly (40 comes before 5). 但是,数字将无法正确排序(40在5之前)。 To sort numbers, you must add a function that compare numbers. 要对数字进行排序,您必须添加一个比较数字的函数。

Simply amazing... so a custom sort is required even for an array of integers. 简直太棒了......所以即使对于一个整数数组也需要自定义排序。

Javascript's sort sorts by default lexicographical, alphabetical. Javascript的排序默认排序词典,按字母顺序排列。 Thus as I understand it every element is treated as a string. 因此,据我所知,每个元素都被视为一个字符串。 The internal sorting algorithm is most probably quicksort or mergesort. 内部排序算法很可能是快速排序或合并排序。 To be able to use quicksort you need to be able to relate elements to each other, is a bigger than b? 为了能够使用quicksort你需要能够将元素相互关联,是否比b更大? In the string case this ordering is already implemented. 在字符串的情况下,这种排序已经实现。

Since you might want to sort your custom datatypes etc. you can provide a functional defining how to order two elements. 由于您可能希望对自定义数据类型等进行排序,因此可以提供定义如何对两个元素进行排序的功能。

From your example your functional determines the order of two numbers a and b. 从您的示例中,您的函数确定两个数字a和b的顺序。 Javascript sort then uses your function telling sort how to order the elements. Javascript sort然后使用您的函数告诉排序如何排序元素。

Turns out that mergesort is used by Mozilla, look at: Javascript Array.sort implementation? 原来,Mozilla使用mergesort,看看: Javascript Array.sort实现?

The problem lies with the use of strings to represent numbers, which the sort function unfortunately does as default. 问题在于使用字符串来表示数字,排序函数不幸的是默认情况下这样做。 Strings are sorted alphabetically. 字符串按字母顺序排序。 The comparison function in your code just forces the strings to be evaluated as numbers. 代码中的比较函数只强制将字符串计算为数字。

I'd consider it very bad API design that the sort function defaults to treating the elements as strings, but it may be necessary given JavaScript's loose type system.. 我认为非常糟糕的API设计,sort函数默认将元素视为字符串,但在给定JavaScript的松散类型系统时可能是必要的。

The function sort will sort your array in an alphabetical sort order , even if it consists of integers; 函数sort将按字母顺序对数组进行排序 ,即使它由整数组成; that's the reason why your array is sorted like that by calling sort without a parameter. 这就是为什么你的数组通过调用不带参数的sort来排序的原因。

sortOrder is a comparison function that is used to define a new sort order for the array; sortOrder是一个比较函数,用于为数组定义新的排序顺序; this function will return 这个功能会回来

  • 0 , if a and b are of the same value 0 ,如果ab具有相同的值
  • a value > 0 , if a has a bigger value than b 如果a的值大于b ,则值> 0
  • a value < 0 , if a has a smaller value than b 如果a的值小于b ,则值< 0

In JavaScript, "1" - "2" will return -1 , which is a number, and not a string anymore; 在JavaScript中, "1" - "2"将返回-1 ,这是一个数字,而不是字符串; by using the comparison function sortOrder on your array consisting of numbers wrapped in strings , you're ordering the array in a numerical sort order , thus resulting in 1,5,10,25,40,100 , and not in 1,10,100,25,40,5 通过在包含字符串数字的数组上使用比较函数sortOrder ,您1,10,100,25,40,5 数字排序顺序对数组进行排序 ,从而得到1,5,10,25,40,100 ,而不是1,10,100,25,40,5

You can delegate the sorting to your own sort function: 您可以将排序委派给您自己的排序函数:

function sortnum(a,b) {
 return parseInt(a,10)-parseInt(b,10);
}
var n = ["10", "5", "40", "25", "100", "1"];
alert(n.sort(sortnum)); //=>["1", "5", "10", "25", "40", "100"]

如果您的n定义为:

var n = [10, 5, 40, 25, 100, 1]; 

The “default” comparison function calls toString on both values and does a lexicographical comparison on the string representations. “默认”比较函数在两个值上调用toString,并对字符串表示进行字典比较。 V8 engine uses Timsort algorithms which runs in O(nlogn). V8引擎使用在O(nlogn)中运行的Timsort算法。 Source 资源

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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