Introdução
Muitos desenvolvedores de JavaScript tiveram a experiência de classificar dados no lado do cliente. Infelizmente, as bibliotecas existentes têm pequenas falhas. Mas essas deficiências se somam e limitam a maneira como os programadores pensam sobre a classificação. Para superar essas limitações, vamos examinar a classificação em diferentes idiomas. Munidos desse conhecimento, seremos capazes de escolher a interface mais conveniente e rigorosa.
Como tudo comeƧou
Em um belo dia de verão, em um projeto com AngularJS, recebi a tarefa de adicionar uma função de classificação a uma tabela. Nesse caso, pode haver vÔrios critérios de classificação ao mesmo tempo, e a direção de cada critério pode ser independente.
Lista de requisitos:
use vÔrias expressões como uma chave para classificação
a capacidade de especificar a direção da classificação de forma independente para cada uma das chaves
a capacidade de classificar strings sem distinção entre maiúsculas e minúsculas e com diferenciação de local
estabilidade de classificação
O que o AngularJS nos oferece para classificação? filtro: documentação orderBy
{{ orderBy_expression | orderBy : expression : reverse : comparator }}
$filter('orderBy')(collection, expression, reverse, comparator)
Example:
<tr ng-repeat="friend in friends | orderBy:'-age'">...</tr>
. , -
, , . , . , ? , , JS, . AngularJS, eval
, . AngularJS JS. , TypeScript . expression
, , . , . , .
, ā reverse
. ! , . , .
ā comparator
, . , comparator
. localeSensitiveComparator
.
, , TypeScript ? JavaScript , , -.
lodash
lodash
, _.sortBy
, .
var users = [
{ 'user': 'fred', 'age': 48 },
{ 'user': 'barney', 'age': 36 },
{ 'user': 'fred', 'age': 40 },
{ 'user': 'barney', 'age': 34 }
];
_.sortBy(users, [(o) => o.user]);
// => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
_.sortBy(users, ['user', 'age']);
// => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]
, , ? - lodash
, _.orderBy
.
This method is like
_.sortBy
except that it allows specifying the sort orders of the iteratees to sort by.
, . :
// Sort by `user` in ascending order and by `age` in descending order.
_.orderBy(users, ['user', 'age'], ['asc', 'desc']);
// => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
ā , . , , .
, _.orderBy
.
Array#sort
JavaScript, Array
sort
. . . , . , , ā . . , .
items.sort(function(a, b) {
if (b.salary < a.salary) {
return -1;
}
if (b.salary > a.salary) {
return 1;
}
if (a.id < b.id) {
return -1;
}
if (a.id > b.id) {
return 1;
}
return 0;
});
// , `lodash`
// :
lodash.orderBy(items, ['salary', 'id'], ['desc', 'asc']);
, , . , .
, .
SQL / SEQUEL
, , . , , ! , SQL.
, SQL 1976 , . , , ?
SELECT EMPNO,NAME,SAL
FROM EMP
WHERE DNO 50
ORDER BY EMPNO
SQL , :
SELECT EMPNO,NAME,SAL
FROM EMP
ORDER BY SAL DESC, EMPNO ASC
Haskell Rust
Haskell Rust :
Haskell sortOn:
import Data.Ord (Down)
import Data.Sort (sortOn)
sortOn (\employee -> (Down (salary employee), employee_id employee)) employees
Rust slice::sort_by_key:
use std::cmp::{Reverse};
slice.sort_by_key(|employee| (Reverse(employee.salary), employee.id))
, ā (newtype) Down Reverse, . , .
Python
Python list.sort sorted, key
.
sorted(employees, key=lambda employee: (employee.salary, employee.id))
Python, Haskell Rust, , . , , - . , , .
from ord_reverse import Reverse
sorted(employees, key=lambda employee: (Reverse(employee.salary), employee.id))
Java C#
Java Arrays.sort
Comparator
( ). Comparator
, , thenComparing
. reversed
.
Comparator<Employee> comparator = Comparator.comparing(Employee.getSalary).reversed() .thenComparing(Employee.getId); Arrays.sort(array, comparator);
ā . ORDER BY SALARY ASC, ID DESC
:
// 1, ,
Comparator<Employee> comparator =
Comparator.comparing(Employee.getSalary)
.thenComparing(Comparator.comparing(Employee.getId).reversed());
// 2, .
// .
Comparator<Employee> comparator =
Comparator.comparing(Employee.getSalary).reversed()
.thenComparing(Employee.getId).reversed();
LINQ Query, SQL, C# Enumerable.OrderBy
Enumerable.OrderByDescending
, Enumerable.ThenBy
Enumerable.ThenByDescending
.
IEnumerable<Employee> query = employees .OrderByDescending(employee => employee.Salary) .ThenBy(employee => employee.Id);
Java . ā , : IEnumerable
ā 4 , 1 Haskell/Rust/Python. C# , .
, Java, C# . , .
C C++
C qsort:
#include <stdlib.h>
int cmp_employee(const void *p1, const void *p2)
{
const employee *a = (employee*)p1;
const employee *b = (employee*)p2;
if (b->salary < a->salary) {
return -1;
}
if (b->salary > a->salary) {
return 1;
}
if (a->id < b->id) {
return -1;
}
if (a->id > b->id) {
return 1;
}
return 0;
}
/* ... */
qsort(employees, count, sizeof(employee), cmp_employee);
C++ std::sort:
#include <algorithm>
/* ... */
std::sort(employees.begin(), employees.end(), [](const employee &a, const employee &b) {
if (b->salary < a->salary) {
return true;
}
if (b->salary > a->salary) {
return false;
}
return a->id < b->id;
});
C, C++ . C ( , ), C++ ā . - , . , C++ .
C C++ . Array#sort
, , .
, Haskell Rust. JavaScript?
JS , , JS . , . ?
sortBy(array, (employee) => [{ reverse: employee.salary }, employee.id]);
JavaScript
, . JavaScript , , Trait
- typeclass
-, , .
:
null
.Maybe
Option
.
, .
NaN
.
, , BigInt JavaScript.
, .
{ reverse: xxx }
,xxx
.Down
/Reverse
{ localeCompare: sss, collator: ccc }
,sss
ccc
. .
.
- , . .
, ā : better-cmp
: X?
orderBy: "Inspired by Angular's orderBy filter", . .
thenby: , Java , - .
multisort: ą² _ą²
if (/[^\(\r\n]*\([^\(\r\n]*\)$/.test(nextKey)) { var indexOfOpenParenthesis = nextKey.indexOf("("); var args = JSON.parse("[" + nextKey.slice(indexOfOpenParenthesis+1, -1) + "]"); nextKey = nextKey.slice(0, indexOfOpenParenthesis); }
, .
.
" " JavaScript .
A melhor solução JavaScript que eu poderia fazer agora estĆ” incorporada na biblioteca better-cmp disponĆvel no npm.