У меня есть следующая таблица, которая пытается сортировать по возрастанию и убыванию порядка onclick
со следующим кодом JavaScript:
function sortTable(n) {
var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
table = document.getElementById("myTable");
switching = true;
//Set the sorting direction to ascending:
dir = "asc";
/*Make a loop that will continue until
no switching has been done:*/
while (switching) {
//start by saying: no switching is done:
switching = false;
rows = table.getElementsByTagName("TR");
/*Loop through all table rows (except the
first, which contains table headers):*/
for (i = 1; i < (rows.length - 1); i++) {
//start by saying there should be no switching:
shouldSwitch = false;
/*Get the two elements you want to compare,
one from current row and one from the next:*/
x = rows[i].getElementsByTagName("TD")[n];
y = rows[i + 1].getElementsByTagName("TD")[n];
/*check if the two rows should switch place,
based on the direction, asc or desc:*/
if (dir == "asc") {
if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
//if so, mark as a switch and break the loop:
shouldSwitch = true;
break;
}
} else if (dir == "desc") {
if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) {
//if so, mark as a switch and break the loop:
shouldSwitch = true;
break;
}
}
}
if (shouldSwitch) {
/*If a switch has been marked, make the switch
and mark that a switch has been done:*/
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
switching = true;
//Each time a switch is done, increase this count by 1:
switchcount++;
} else {
/*If no switching has been done AND the direction is "asc",
set the direction to "desc" and run the while loop again.*/
if (switchcount == 0 && dir == "asc") {
dir = "desc";
switching = true;
}
}
}
}
<div class="table-responsive">
<table class="table table-striped" id="myTable">
<tr>
<th onclick="sortTable(0)">Date <i class='fa fa-caret-down'></i></th>
<th onclick="sortTable(1)">Views <i class='fa fa-caret-down'></i></th>
<th onclick="sortTable(2)">Clicks <i class='fa fa-caret-down'></i></th>
<th onclick="sortTable(3)">CTR <i class='fa fa-caret-down'></i></th>
<th onclick="sortTable(4)">Earned <i class='fa fa-caret-down'></i></th>
<th onclick="sortTable(5)">eCPM <i class='fa fa-caret-down'></i></th>
</tr>
<tr>
<td>2017-11-30</td>
<td>4133</td>
<td>3</td>
<td>0.07%</td>
<td>$0.03</td>
<td>$0.0073</td>
</tr>
<tr>
<td>2017-11-29</td>
<td>8340</td>
<td>5</td>
<td>0.06%</td>
<td>$0.05</td>
<td>$0.006</td>
</tr>
<tr>
<td>2017-11-28</td>
<td>7410</td>
<td>5</td>
<td>0.07%</td>
<td>$0.025</td>
<td>$0.0034</td>
</tr>
<tr>
<td>2017-11-27</td>
<td>3796</td>
<td>2</td>
<td>0.05%</td>
<td>$0.01</td>
<td>$0.0026</td>
</tr>
<tr>
<td>2017-11-26</td>
<td>4005</td>
<td>2</td>
<td>0.05%</td>
<td>$0.01</td>
<td>$0.0025</td>
</tr>
<tr>
<td>2017-11-25</td>
<td>2070</td>
<td>2</td>
<td>0.1%</td>
<td>$0.01</td>
<td>$0.0048</td>
</tr>
<tr>
<td>2017-11-24</td>
<td>1016</td>
<td>6</td>
<td>0.59%</td>
<td>$0.03</td>
<td>$0.0295</td>
</tr>
<tr>
<td>2017-11-23</td>
<td>1503</td>
<td>4</td>
<td>0.27%</td>
<td>$0.02</td>
<td>$0.0133</td>
</tr>
<tr>
<td>2017-11-22</td>
<td>1665</td>
<td>11</td>
<td>0.66%</td>
<td>$0.055</td>
<td>$0.033</td>
</tr>
<tr>
<td>2017-11-21</td>
<td>1340</td>
<td>10</td>
<td>0.75%</td>
<td>$0.05</td>
<td>$0.0373</td>
</tr>
<tr>
<td>2017-11-20</td>
<td>1489</td>
<td>13</td>
<td>0.87%</td>
<td>$0.065</td>
<td>$0.0437</td>
</tr>
<tr>
<td>2017-11-19</td>
<td>1745</td>
<td>5</td>
<td>0.29%</td>
<td>$0.025</td>
<td>$0.0143</td>
</tr>
<tr>
<td>2017-11-18</td>
<td>962</td>
<td>5</td>
<td>0.52%</td>
<td>$0.025</td>
<td>$0.026</td>
</tr>
<tr>
<td>2017-11-17</td>
<td>779</td>
<td>8</td>
<td>1.03%</td>
<td>$0.04</td>
<td>$0.0513</td>
</tr>
</table>
</div>
Проблема здесь в том, что она работает правильно с одинаковым количеством цифр, но не с разным количеством цифр. Например, если столбец содержит: 1, 5, 3
Он сортируется так, как ожидалось. 1, 3, 5
и 5, 3, 1
Но если столбец содержит: 5, 3, 11
Он сортируется как: 11, 3, 5
и 5, 3, 11
Как правильно их отсортировать?
Поскольку у вас есть несколько разных форматов, то, что вы, вероятно, захотите сделать, это попытаться извлечь цифровую часть числа.
Вы можете попытаться сделать это с помощью RegExp, проверив общие числовые шаблоны и затем проанализируя простой номер. Если бы я архивировал это, у меня, вероятно, был бы массив различных функций сопоставления и преобразования для каждого поддерживаемого формата.
Что-то вроде этого:
const patterns = [
{ test: /\$[0-9\.,]+/, transform: str => parseFloat(str.replace(/[$,]/g, '')) },
{ test: /[0-9\.,]+%/, transform: str => parseFloat(str.replace(/[%,]/g, '')) }
];
const convert = str => {
const pattern = patterns.find(({ test }) => test.test(str));
return pattern && pattern.transform(str) || str;
};
const converted = ['$1,234.56', '1,234.56%', 'not a num'].map(str => convert(str));
console.log(converted);
Затем, для каждого поля, пропустите его через все шаблоны, пока не найдете совпадение, не конвертируйте их, а затем выполните числовую сортировку. Вы также можете оставить те, которые не преобразуются в виде строк, и пусть это просто делает для них похожий на строку тип.
В вашем коде, если вы использовали что-то вроде меня, вы просто изменили бы сравнительные строки на что-то вроде этого:
if (convert(x.innerHTML.toLowerCase()) > convert(y.innerHTML.toLowerCase()))
Кроме того, совет для дат: я бы рекомендовал преобразовать даты в временные метки или общий формат (например, YYYY-MM-DD HH:MM:SS
, который является самым большим до наименьшего), который затем позволит вам правильно сравнивать и сортировать несколько форматов даты в одном столбце.
Ниже был оригинальный ответ, который не учитывал символы с номерами.
Ваша проблема в том, что вы выполняете сравнение строк вместо численного сравнения.
Сравнение строк будет сортировать строки так же, как и алфавиты. Например, все, что начинается с 1, всегда будет предшествовать чему-либо, начинающемуся с 2, даже если это "1365872685623876723" против "2".
Вместо этого измените эти строки:
x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()
Сначала проанализировать их на номера с помощью parseInt()
:
parseInt(x.innerHTML.toLowerCase()) > parseInt(y.innerHTML.toLowerCase())
Это сделает его численным.
%
и $
выиграет, так как parseInt()
не решает проблему. Требуемое решение должно быть более сложным, когда OP, скорее всего, должен хранить фактическое необработанное число внутри атрибута данных или аналогичного и сортировать его вместо этого. Хотя десятичные значения могут потенциально вызывать другое решение, отличное от parseInt
'1', '11','2' etc..
не числа1,2,11,etc...