Introducción
Muchos desarrolladores de JavaScript han tenido la experiencia de ordenar datos en el lado del cliente. Desafortunadamente, las bibliotecas existentes tienen fallas menores. Pero estas deficiencias se suman y limitan la forma en que los programadores piensan sobre la clasificación. Para superar estas limitaciones, veamos la clasificación en diferentes idiomas. Armados con este conocimiento, podremos elegir la interfaz más conveniente y rigurosa.
Cómo empezó todo
Un buen día de verano, en un proyecto con AngularJS, se me asignó la tarea de agregar una función de ordenación a una tabla. En este caso, puede haber varios criterios para ordenar a la vez, y la dirección de cada criterio puede ser independiente.
Lista de requisitos:
utilizar varias expresiones como clave para ordenar
la capacidad de especificar la dirección de clasificación de forma independiente para cada una de las claves
la capacidad de ordenar cadenas que no distinguen entre mayúsculas y minúsculas y distinguen la configuración regional
-
¿Qué nos ofrece AngularJS para clasificar? filter: orderBy documentation
{{ 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 .
La mejor solución de JavaScript que pude hacer ahora está incorporada en la biblioteca better-cmp disponible en npm.