对多维数组进行排序不能处理小数
Sorting a multi-dimensional array doesn't work with decimals
这个问题与这个问题有关,并且基于这个问题的脚本:如何在JavaScript中按多列对多维数组进行排序?我的解决方案在当时是有效的(至少我相信是这样),但在对我们的自定义标签进行了一系列更改以使其跨浏览器兼容之后,我现在遇到了一个新问题。
所以我有下面的一段代码。很抱歉篇幅太长;这是我在复制问题的同时尽可能简化它:
<table border=1>
<tr style="font-weight:bold;">
<td>Begin Text</td>
<td>Begin Number</td>
<td>Sorted Text</td>
<td>Sorted Number</td>
</tr>
<tr>
<td id="r1c1"></td>
<td id="r1c2"></td>
<td id="r1c3"></td>
<td id="r1c4"></td>
</tr>
<tr>
<td id="r2c1"></td>
<td id="r2c2"></td>
<td id="r2c3"></td>
<td id="r2c4"></td>
</tr>
<tr>
<td id="r3c1"></td>
<td id="r3c2"></td>
<td id="r3c3"></td>
<td id="r3c4"></td>
</tr>
<tr>
<td id="r4c1"></td>
<td id="r4c2"></td>
<td id="r4c3"></td>
<td id="r4c4"></td>
</tr>
<tr>
<td id="r5c1"></td>
<td id="r5c2"></td>
<td id="r5c3"></td>
<td id="r5c4"></td>
</tr>
<tr>
<td id="r6c1"></td>
<td id="r6c2"></td>
<td id="r6c3"></td>
<td id="r6c4"></td>
</tr>
<tr>
<td id="r7c1"></td>
<td id="r7c2"></td>
<td id="r7c3"></td>
<td id="r7c4"></td>
</tr>
<tr>
<td id="r8c1"></td>
<td id="r8c2"></td>
<td id="r8c3"></td>
<td id="r8c4"></td>
</tr>
<tr>
<td><input type="button" onclick="testSort(1);" value="Sort"></td>
<td><input type="button" onclick="testSort(2);" value="Sort"></td>
</tr>
</table>
<script>
function testSort(orderCol) {
orderList = [orderCol];
dataArr = do2DArraySort(dataArr, orderList, 'desc');
for (x=1; x<=numRows; x++) {
document.getElementById('r' + x + 'c3').innerHTML = dataArr[x-1][1];
document.getElementById('r' + x + 'c4').innerHTML = dataArr[x-1][2];
}
}
function TwoDimensionalArray(iRows, iCols) {
var i;
var j;
var a = new Array(iRows);
for (i=0; i < iRows; i++) {
a[i] = new Array(iCols);
for (j=0; j < iCols; j++) {
a[i][j] = "";
}
}
return(a);
}
function do2DArraySort(dataArr, orderList, orderDir) {
//Loop over each item in the list of sort columns. For each one invoke the sort method on the array using the appropriate function.
for (x=orderList.length-1; x >= 0; x--) {
if (orderDir[x] == 'asc') {
dataArr.sort(sortMethodFunctionAsc);
} else {
dataArr.sort(sortMethodFunctionDesc);
}
}
return dataArr;
}
function checkSortValues(a, b) {
var dataType = 'Text';
if ((IsNumeric(a) && IsNumeric(b)) || (a == null && IsNumeric(b)) || (IsNumeric(a) && b == null)) {
dataType = 'Numeric';
}
if ((IsDate(a) && IsDate(b)) || (a == null && IsDate(b)) || (IsDate(a) && b == null)) {
dataType = 'Date';
}
return dataType;
}
function sortMethodFunctionAsc(a, b) {
if (checkSortValues(a[orderList[x]], b[orderList[x]]) == 'Numeric') {
//If the values are numeric, simply check which is larger than the other.
return a[orderList[x]] - b[orderList[x]];
} else if (checkSortValues(a[orderList[x]], b[orderList[x]]) == 'Date') {
//If the values are dates they need converted to date objects. 95% of the time this is not necessary as they are already passed in as dates,
//but the conversion is required to catch the few cases when they are not.
var a2 = new Date(a[orderList[x]]);
var b2 = new Date(b[orderList[x]]);
//The getTime method is used to convert the dates into millisecond ticker equivalents for easier comparison.
return a2.getTime() - b2.getTime();
} else {
//If one of the values is a string, convert both to a string and compare alphabetically.
if (a[orderList[x]].toString() > b[orderList[x]].toString()) {
return 1;
} else if (a[orderList[x]].toString() < b[orderList[x]].toString()) {
return -1;
} else {
//If they are the same, tell the sort to skip them.
return 0;
}
}
}
function sortMethodFunctionDesc(a, b) {
//This function is identical to the ascending one, but the comparison operators are reversed.
if (checkSortValues(a[orderList[x]], b[orderList[x]]) == 'Numeric') {
return b[orderList[x]] - a[orderList[x]];
} else if (checkSortValues(a[orderList[x]], b[orderList[x]]) == 'Date') {
var a2 = new Date(a[orderList[x]]);
var b2 = new Date(b[orderList[x]]);
return b2.getTime() - a2.getTime();
} else {
if (a[orderList[x]].toString() < b[orderList[x]].toString()) {
return 1;
} else if (a[orderList[x]].toString() > b[orderList[x]].toString()) {
return -1;
} else {
return 0;
}
}
}
function IsNumeric(input) {
return (input - 0) == input && input.length > 0;
}
function IsDate(testValue) {
var returnValue = false;
var testDate;
try {
testDate = new Date(testValue);
if (!isNaN(testDate)) {
returnValue = true;
} else {
returnValue = false;
}
}
catch (e) {
returnValue = false;
}
return returnValue;
}
numRows = 8;
orderList = [1];
dataArr = TwoDimensionalArray(numRows, 2);
dataArr[0][1] = 'Jimbo';
dataArr[0][2] = 3;
dataArr[1][1] = 'Jim';
dataArr[1][2] = 0.65;
dataArr[2][1] = 'Jackie';
dataArr[2][2] = 1.25;
dataArr[3][1] = 'John';
dataArr[3][2] = 0.8;
dataArr[4][1] = 'Jacob';
dataArr[4][2] = 0.95;
dataArr[5][1] = 'Jill';
dataArr[5][2] = 0.85;
dataArr[6][1] = 'Jan';
dataArr[6][2] = 0.8;
dataArr[7][1] = 'Jamie';
dataArr[7][2] = 1.45;
for (x=1; x<=numRows; x++) {
document.getElementById('r' + x + 'c1').innerHTML = dataArr[x-1][1];
document.getElementById('r' + x + 'c2').innerHTML = dataArr[x-1][2];
}
</script>
如果你在浏览器中打开它,你会看到一个html表格,它按照输入的顺序(即:随机)吐出每个数组列。如果单击列底部的任何一个按钮,它将对数据进行排序,并将其放在第3列和第4列中。我的实际应用程序擦除并重新加载表,但这用于演示目的。
单击文本列底部的排序按钮可以正常工作;它按名称的字母顺序对数组进行排序。但是,如果您对数字列进行排序,您将看到顺序上的变化,但绝不是正确的。每次结果都是一样的,但是如果您立即或在文本搜索之后单击数字排序(因为搜索是基于数组的当前状态而不是原始数组),则结果会有所不同。这正是我在我的应用程序中看到的。
我花了一些时间来缩小范围,但这是我确定的:
1)文本、日期和整数排序良好;
2)小数按照第一个数字排序,忽略小数点之后的数据。
3)多列排序工作得很好,但显示出同样的异常,所以我将其简化为本例中的单列排序。
我已经盯着这个看了几个小时了,但是没有运气,我需要一个新的眼睛。为什么是我的数组。排序功能不能正常工作?
您的checkSortValues
函数中存在问题,一旦数据类型设置为数字,则也会对日期进行测试。
同样,在IsNumeric测试中有一个错误,其中input.length
将返回undefined。你应该注释掉/更改测试的第二部分。
function IsNumeric(input) {
return (input - 0) == input // && input.length > 0;
}
如果您更改IsNumeric
测试,如果您使用else if
而不是if
进行日期测试,我认为它解决了您的问题。
function checkSortValues(a, b) {
var dataType = 'Text';
if ((IsNumeric(a) && IsNumeric(b)) || (a == null && IsNumeric(b)) || (IsNumeric(a) && b == null)) {
dataType = 'Numeric';
}
else if ((IsDate(a) && IsDate(b)) || (a == null && IsDate(b)) || (IsDate(a) && b == null)) {
dataType = 'Date';
}
return dataType;
}
编辑:包括完整的代码与我建议的修改…
我已经测试过了,它对我有效,以正确的顺序排序。
<table border=1>
<tr style="font-weight:bold;">
<td>Begin Text</td>
<td>Begin Number</td>
<td>Sorted Text</td>
<td>Sorted Number</td>
</tr>
<tr>
<td id="r1c1"></td>
<td id="r1c2"></td>
<td id="r1c3"></td>
<td id="r1c4"></td>
</tr>
<tr>
<td id="r2c1"></td>
<td id="r2c2"></td>
<td id="r2c3"></td>
<td id="r2c4"></td>
</tr>
<tr>
<td id="r3c1"></td>
<td id="r3c2"></td>
<td id="r3c3"></td>
<td id="r3c4"></td>
</tr>
<tr>
<td id="r4c1"></td>
<td id="r4c2"></td>
<td id="r4c3"></td>
<td id="r4c4"></td>
</tr>
<tr>
<td id="r5c1"></td>
<td id="r5c2"></td>
<td id="r5c3"></td>
<td id="r5c4"></td>
</tr>
<tr>
<td id="r6c1"></td>
<td id="r6c2"></td>
<td id="r6c3"></td>
<td id="r6c4"></td>
</tr>
<tr>
<td id="r7c1"></td>
<td id="r7c2"></td>
<td id="r7c3"></td>
<td id="r7c4"></td>
</tr>
<tr>
<td id="r8c1"></td>
<td id="r8c2"></td>
<td id="r8c3"></td>
<td id="r8c4"></td>
</tr>
<tr>
<td><input type="button" onclick="testSort(1);" value="Sort"></td>
<td><input type="button" onclick="testSort(2);" value="Sort"></td>
</tr>
</table>
<script>
function testSort(orderCol) {
orderList = [orderCol];
dataArr = do2DArraySort(dataArr, orderList, 'desc');
for (x=1; x<=numRows; x++) {
document.getElementById('r' + x + 'c3').innerHTML = dataArr[x-1][1];
document.getElementById('r' + x + 'c4').innerHTML = dataArr[x-1][2];
}
}
function TwoDimensionalArray(iRows, iCols) {
var i;
var j;
var a = new Array(iRows);
for (i=0; i < iRows; i++) {
a[i] = new Array(iCols);
for (j=0; j < iCols; j++) {
a[i][j] = "";
}
}
return(a);
}
function do2DArraySort(dataArr, orderList, orderDir) {
//Loop over each item in the list of sort columns. For each one invoke the sort method on the array using the appropriate function.
for (x=orderList.length-1; x >= 0; x--) {
if (orderDir[x] == 'asc') {
dataArr.sort(sortMethodFunctionAsc);
} else {
dataArr.sort(sortMethodFunctionDesc);
}
}
return dataArr;
}
function checkSortValues(a, b) {
var dataType = 'Text';
if ((IsNumeric(a) && IsNumeric(b)) || (a == null && IsNumeric(b)) || (IsNumeric(a) && b == null)) {
dataType = 'Numeric';
}
else if ((IsDate(a) && IsDate(b)) || (a == null && IsDate(b)) || (IsDate(a) && b == null)) {
dataType = 'Date';
}
return dataType;
}
function sortMethodFunctionAsc(a, b) {
if (checkSortValues(a[orderList[x]], b[orderList[x]]) == 'Numeric') {
//If the values are numeric, simply check which is larger than the other.
return a[orderList[x]] - b[orderList[x]];
} else if (checkSortValues(a[orderList[x]], b[orderList[x]]) == 'Date') {
//If the values are dates they need converted to date objects. 95% of the time this is not necessary as they are already passed in as dates,
//but the conversion is required to catch the few cases when they are not.
var a2 = new Date(a[orderList[x]]);
var b2 = new Date(b[orderList[x]]);
//The getTime method is used to convert the dates into millisecond ticker equivalents for easier comparison.
return a2.getTime() - b2.getTime();
} else {
//If one of the values is a string, convert both to a string and compare alphabetically.
if (a[orderList[x]].toString() > b[orderList[x]].toString()) {
return 1;
} else if (a[orderList[x]].toString() < b[orderList[x]].toString()) {
return -1;
} else {
//If they are the same, tell the sort to skip them.
return 0;
}
}
}
function sortMethodFunctionDesc(a, b) {
//This function is identical to the ascending one, but the comparison operators are reversed.
if (checkSortValues(a[orderList[x]], b[orderList[x]]) == 'Numeric') {
return b[orderList[x]] - a[orderList[x]];
} else if (checkSortValues(a[orderList[x]], b[orderList[x]]) == 'Date') {
var a2 = new Date(a[orderList[x]]);
var b2 = new Date(b[orderList[x]]);
return b2.getTime() - a2.getTime();
} else {
if (a[orderList[x]].toString() < b[orderList[x]].toString()) {
return 1;
} else if (a[orderList[x]].toString() > b[orderList[x]].toString()) {
return -1;
} else {
return 0;
}
}
}
function IsNumeric(input) {
return (input - 0) == input// && input.length > 0;
}
function IsDate(testValue) {
var returnValue = false;
var testDate;
try {
testDate = new Date(testValue);
if (!isNaN(testDate)) {
returnValue = true;
} else {
returnValue = false;
}
}
catch (e) {
returnValue = false;
}
return returnValue;
}
numRows = 8;
orderList = [1];
dataArr = TwoDimensionalArray(numRows, 2);
dataArr[0][1] = 'Jimbo';
dataArr[0][2] = 3;
dataArr[1][1] = 'Jim';
dataArr[1][2] = 0.65;
dataArr[2][1] = 'Jackie';
dataArr[2][2] = 1.25;
dataArr[3][1] = 'John';
dataArr[3][2] = 0.8;
dataArr[4][1] = 'Jacob';
dataArr[4][2] = 0.95;
dataArr[5][1] = 'Jill';
dataArr[5][2] = 0.85;
dataArr[6][1] = 'Jan';
dataArr[6][2] = 0.8;
dataArr[7][1] = 'Jamie';
dataArr[7][2] = 1.45;
for (x=1; x<=numRows; x++) {
document.getElementById('r' + x + 'c1').innerHTML = dataArr[x-1][1];
document.getElementById('r' + x + 'c2').innerHTML = dataArr[x-1][2];
}
</script>
我不知道日期,但字符串和数字都可以排序:
if (a < b) {
return 1;
} else if (b > a) {
return -1;
} else {
return
}
<
和>
适用于两种数据类型。我在你的代码中改变了这一点,它工作得很好:http://jsfiddle.net/Ft44x/6/我已经改变了sortDesc函数。任何其他的bug都可能是由于你的代码太复杂造成的,清理它!
同样,反过来排序只是:不需要实现同样的事情两次。
function sortAsc() {
... // implement
}
function sortDesc(a, b) {
return -1 * sortAsc(a,b);
}
另外,如果你有一个数字,不要把它存储为字符串,那就太愚蠢了。
var my_string = "foo";
var my_number = 42; // no quotes
var my_decimal = 0.63;
还有一件事,如果你需要知道某个东西是否是日期,为什么不使用instanceof
呢?
var date = new Date();
alert(date instanceof Date); // should be true
你可以对字符串和数字做同样的事情,但你甚至不需要:p
- 如何使用 javascript 按列对表进行排序?不能在这里使用 jquery.我正在使用javascript从xml文
- Rails3-可排序列表不能与wysihtml5一起工作
- 为什么不能关闭我的数据表的排序
- 表格排序器可单击,但不能排序
- Jquery ui可排序不'不能正确交换
- 选择排序不能正常工作
- 不能排除用于排序的元素
- 为什么调用不能作为排序函数
- jQuery排序功能不能正常工作
- 对多维数组进行排序不能处理小数
- jQuery UI + Bootstrap 3排序手风琴不能正常工作
- 排序dgrid列不能按预期工作
- 排序数组对象与点,字母,数字.我能按数字排序,但混合值很难排序.不确定是否有可能做对
- jQuery表排序器不能处理由AJAX获取的值
- 引导数据表排序不能正常工作
- 是否可以调用两个函数,如果ext.form.checkbox被选中?或者为什么我在openlayers中的层不能重新排序
- Javascript排序不能正确处理字符串
- 光滑网格列重新排序不能正确工作
- jQuery排序不能在嵌套链接上工作
- 使用数据表按两列排序(不能读取property ' style '未定义)