Résoudre le tri JavaScript une fois pour toutes

introduction

De nombreux développeurs JavaScript ont eu l'expérience du tri des données côté client. Malheureusement, les bibliothèques existantes présentent des défauts mineurs. Mais ces lacunes s'additionnent et limitent la façon dont les programmeurs pensent au tri. Pour surmonter ces limitations, examinons le tri dans différentes langues. Forts de ces connaissances, nous pourrons choisir l'interface la plus pratique et la plus rigoureuse.





Comment tout a commencé

Un beau jour d'été, sur un projet avec AngularJS, j'ai été chargé d'ajouter une fonction de tri à une table. Dans ce cas, il peut y avoir plusieurs critères de tri à la fois et le sens de chaque critère peut être indépendant.





Liste des exigences:





  • utiliser plusieurs expressions comme clé de tri





  • la possibilité de spécifier le sens de tri indépendamment pour chacune des clés





  • la possibilité de trier les chaînes insensible à la casse et sensible aux paramètres régionaux





  • stabilité du tri





Que nous propose AngularJS pour le tri? 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
      
      



. , SQL .





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



.





cmp, .





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



-, , .





:





  1. null



    . Maybe



    Option



    .





  2. , .





  3. NaN



    .





  4. , , BigInt JavaScript.





  5. , .





  6. { reverse: xxx }



    , xxx



    . Down



    / Reverse







  7. { localeCompare: sss, collator: ccc }



    , sss



    ccc



    . .





  8. .





- , . .





, — : 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 meilleure solution JavaScript que je pourrais faire est maintenant incorporée dans la bibliothèque better-cmp disponible sur npm.








All Articles