How to sort your socks using Javascript

How to sort your socks using Javascript

No matter your experience in JS, you have probably came across the Array#sort method at some point. Do you remember the first time you tried sorting numbers? You were probably astonished that the sort method does not sort things out quite as we might expect.

Believe it or not, there is actually much more going on than meets the eye! Let’s get our computer science hat on and explore some useful sorting algorithms currently implemented by JS engines used by Node such as Chrome's V8 and Microsoft's Chakra. As a developer, learning how these algorithms work, why and when to use them will help you create more performant and consistent applications!

7c917eac018306e411041d5533910807?s=128

Claudia Hernández

October 28, 2017
Tweet

Transcript

  1. ¿CÓMO ORDENAR TUS MEDIAS USANDO JAVASCRIPT? NodeConf Argentina Claudia Hernandez

    $ -
  2. @koste4 http://www.bbc.com/news/magazine-37196037

  3. @koste4 Algoritmo que acomoda elementos de una lista en cierto

    orden. Los ordenes más usados son numérico y lexicográfico ALGORITMO
 DE ORDENAMIENTO
  4. @koste4 ARRAY SORT EN JS # 1 myArray = [33,

    2, 98, 25, 4] 2 myArray.sort() // [ 2, 25, 33, 4, 98 ]
  5. @koste4 ORDENAMIENTO LEXICOGRÁFICO Si no se provee , los elementos

    son ordenados convirtiéndolos a strings y comparando la posición del valor Unicode de dichos strings compareFunction D
  6. @koste4 VALOR UNICODE 1 colors = ['red', 'blue'] 2 colors.sort()

    3 // ['blue', 'red'] 4 5 numbers = [80, 9] 6 numbers.sort() 7 // [80, 9] 80 9 = = 56 48 57 00
  7. @koste4 1 colors = ['red', 'blue'] 2 colors.sort() 3 //

    ['blue', 'red'] 4 5 numbers = ['80', '9'] 6 numbers.sort() 7 // [80, 9] VALOR UNICODE 80 9 = = 56 48 57 00
  8. @koste4 ARRAY SORT EN JS # 1 // [ 2,

    25, 33, 4, 98 ]
  9. @koste4 ARRAY SORT EN JS # 1 myArray = [33,

    2, 98, 25, 4] 2 myArray.sort( (a,b) => a - b ) 3 // [ 2, 4, 25, 33, 98 ]
  10. @koste4 ¿ALGUNA VEZ TE HAS CUÁL ES PREGUNTADO EL ALGORITMO

    USADO EN LA FUNCIÓN SORT NATIVA DE ? JAVASCRIPT
  11. https://hg.mozilla.org/mozilla-central/file/28be8df0deb7/js/src/jsarray.cpp M E R G E S O R T

    S O R T S P I D E R 
 M O N K E Y
  12. https://hg.mozilla.org/mozilla-central/file/28be8df0deb7/js/src/jsarray.cpp M E R G E S O R T

    S O R T S P I D E R 
 M O N K E Y
  13. https://hg.mozilla.org/mozilla-central/file/28be8df0deb7/js/src/jsarray.cpp M E R G E S O R T

    S O R T S P I D E R 
 M O N K E Y
  14. https://github.com/v8/v8/blob/master/src/js/array.js Q U I C K S O R T

    S O R T V 8
  15. https://github.com/v8/v8/blob/master/src/js/array.js Q U I C K S O R T

    S O R T V 8
  16. https://trac.webkit.org/browser/trunk/Source/JavaScriptCore/ builtins/ArrayPrototype.js M E R G E S O R

    T N I T R O
  17. https://github.com/Microsoft/ChakraCore/blob/master/ lib/Common/DataStructures/QuickSort.h Q U I C K S O R

    T S O R T C H A K R A
  18. @koste4 Motor JS Algoritmo de Ordenamiento SpiderMonkey F I R

    E F O X Insertion Sort (arreglos pequeños)
 Merge Sort V8 C H R O M E Insertion Sort (arreglos pequeños)
 Quick Sort Nitro S A F A R I Merge Sort Chakra I N T E R N E T E X P L O R E R QuickSort
  19. @koste4 ALGORITMOS DE ORDENAMIENTO

  20. @koste4 ESTABILIDAD Un algoritmo de ordenamiento estable es aquel en

    el cual elementos iguales conservan sus posiciones iniciales después del ordenamiento
  21. @koste4 Insertion Sort 3 Merge Sort Quick Sort 1 2

  22. @koste4 INSERTION SORT El arreglo es recorrido de manera secuencial

    y los elementos no ordenados son movidos e insertados en una sub-lista ordenada que se encuentra en el mismo arreglo
  23. @koste4 1 function InsertionSort(arr) { 2 3 let len =

    arr.length, // número de elementos en el arreglo 4 value, // valor a comparar 5 i, // index de la sección sin ordenar 6 j; // index de la sección ordenada 7 8 for(i = 1; i < len; i++) { 9 10 // guarda el valor actual porque puede cambiar después 11 value = arr[i] 12 13 // Cuando el valor de la sección ordenada es mayor que el valor en la 14 // sección no ordenada, mover todos los elementos en la sección uno 15 // por uno. Esto crea un espacio en el cual insertar el valor. 16 for (j = i - 1; j >= 0 && arr[j] > value; j--) { 17 arr[j+1] = arr[j] 18 } 19 arr[j+1] = value 20 } 21 22 return arr 23 24 }
  24. @koste4 10 LOC

  25. @koste4 DIVIDE Y VENCERÁS Tácticas de Napoleón Bonaparte "Genio Militar"

    Dividir al enemigo en dos y sorprender por un costado 1 3 2 Vencer (atacar) al enemigo pues éste será reducido a la mitad de su tamaño original Concentrar artillería y recursos en un sólo flanco
  26. @koste4 MERGE SORT Divide el arreglo en 2 sub- arreglos

    con n/2 elementos cada uno 1 3 2 Vence (ordena) cada sub- arreglo. Al menos que el arreglo sea suficientemente pequeño, usa recursión Combina las soluciones de los sub-arreglos fusionándolos en un sólo arreglo
  27. 1 function MergeSort(arr) { 2 3 let len = arr.length,

    // número de elementos en el arreglo 4 middle, // mitad del arreglo 5 left, // lado izquierdo del arreglo 6 right // lado derecho del arreglo 7 8 // Arreglos de tamaño 0 y 1 no necesitan ser ordenados 9 if (len < 2) { 10 return arr 11 } 12 13 middle = Math.floor(len/2) 14 15 left = arr.slice(0, middle) // lado izquierdo, de 0 a la mitad 16 right = arr.slice(middle) // lado derecho, de la mitad al final 17 18 return merge(MergeSort(left), MergeSort(right)) 19 20 }
  28. 1 // Fusiona 2 arreglos ya ordenados 2 function merge(left,

    right) { 3 let result = [], 4 i = 0, 5 j = 0 6 7 while(i < left.length && j < right.length) { 8 9 // Elementos en ambos arreglos son comparados uno contra el otro. 10 // El elemento más pequeño es insertado en los resultados. 11 12 // Cada ves que un valor de un arreglo es agregado, su 13 // índice correspondiente es incrementado. 14 15 if(left[i] < right[j]) { 16 result.push(left[i++]) 17 } else { 18 result.push(right[j++]) 19 } 20 } 21 22 // Una vez que uno de los arreglos haya terminado, los elementos 23 // restantes del otro arreglo son agregados a los resultados. 24 25 return result.concat(left.slice(i)).concat(right.slice(j)) 26 27 }
  29. @koste4 23 LOC

  30. @koste4 QUICK SORT Encuentra un pivote 1 3 2 Divide

    el arreglo de manera que todos los elementos menores al pivote estén a la izquierda y los mayores a la derecha del pivote Vence (ordena) los arreglos
  31. 1 // Encuentra un “pivote” en el arreglo para comparar

    2 // todos sus elementos y moverlos antes o después de 3 // dicho pivote dependiendo de sus valores 4 function QuickSort(arr, left = 0, right = arr.length - 1) { 5 let len = arr.length, 6 index 7 8 if(len > 1) { 9 10 index = partition(arr, left, right) 11 12 if(left < index - 1) { 13 QuickSort(arr, left, index - 1) 14 } 15 16 if(index < right) { 17 QuickSort(arr, index, right) 18 } 19 20 } 21 22 return arr 23 24 }
  32. 1 function partition(arr, left, right) { 2 let middle =

    Math.floor((right + left) / 2), 3 pivot = arr[middle], 4 i = left, // Inicializa el apuntador en el primer elemento del arreglo 5 j = right // Inicializa el apuntador en el último elemento del arreglo 6 7 while(i <= j) { 8 // Mueve el apuntador izquierdo a la derecha hasta que el valor 9 // a la isquierda sea más grande que el pivote 10 while(arr[i] < pivot) { 11 i++ 12 } 13 14 // Mueve el apuntador derecho a la izquierda hasta que el valor 15 // a la derecha sea menor que el pivote 16 while(arr[j] > pivot) { 17 j-- 18 } 19 20 // Si el apuntador izquierdo es menor o igual al apuntador derecho, 21 // intercambia valores 22 if(i <= j) { 23 [arr[i], arr[j]] = [arr[j], arr[i]] // ES6 destructuring swap 24 i++ 25 j-- 26 } 27 } 28 29 return i 30 31 }
  33. @koste4 31 LOC

  34. 1 Array.prototype.InsertSort = function() { 2 /* tu implementación aquí

    */ 3 } 4 5 Array.prototype.MergeSort = function() { 6 /* tu implementación aquí */ 7 } 8 9 Array.prototype.QuickSort = function() { 10 /* tu implementación aquí */ 11 } 12 13 myArray.InsertSort() 14 myArray.MergeSort() 15 myArray.QuickSort()
  35. @koste4 Y… 
 ¿POR QUÉ DEBERÍA IMPORTARME?

  36. @koste4 ESTRATEGIAS 
 DE DISEÑO

  37. @koste4

  38. @koste4 $ git bisect start

  39. @koste4 ESTABILIDAD

  40. @koste4

  41. const people = [ { name: 'Yamil Asusta', age: 26

    }, { name: 'Mathias Bynens', age: 54 }, { name: 'Arunesh Chandra', age: 17 }, { name: 'Julián Duque', age: 12 }, { name: 'Michele Garrett', age: 32 }, { name: 'Daniel Gimenez', age: 26 }, { name: 'Claudia Hernández', age: 26 }, { name: 'Jeff Lembeck', age: 11 }, { name: 'Kat Marchán', age: 6 }, { name: 'Karisa McKelvey', age: 26 }, { name: 'Kassandra Perch', age: 26 }, { name: 'Nikhila Ravi', age: 26 }, { name: 'Athan Reines', age: 42 }, { name: 'Bert Spaan', age: 11 }, { name: 'Mariano Vazquez', age: 32 }, ]
  42. people.sort((a,b) => { 
 return a.age - b.age }

  43. @koste4 V8

  44. [{ name: 'Kat Marchán', age: 6 }, { name: 'Jeff

    Lembeck', age: 11 }, { name: 'Bert Spaan', age: 11 }, { name: 'Julián Duque', age: 12 }, { name: 'Arunesh Chandra', age: 17 }, { name: 'Daniel Gimenez', age: 26 }, { name: 'Claudia Hernández', age: 26 }, { name: 'Nikhila Ravi', age: 26 }, { name: 'Yamil Asusta', age: 26 }, { name: 'Karisa McKelvey', age: 26 }, { name: 'Kassandra Perch', age: 26 }, { name: 'Michele Garrett', age: 32 }, { name: 'Mariano Vazquez', age: 32 }, { name: 'Athan Reines', age: 42 }, { name: 'Mathias Bynens', age: 54 }]
  45. @koste4 NITRO

  46. [{ name: 'Kat Marchán', age: 6 }, { name: 'Jeff

    Lembeck', age: 11 }, { name: 'Bert Spaan', age: 11 }, { name: 'Julián Duque', age: 12 }, { name: 'Arunesh Chandra', age: 17 }, { name: 'Yamil Asusta', age: 26 }, { name: 'Daniel Gimenez', age: 26 }, { name: 'Claudia Hernández', age: 26 }, { name: 'Karisa McKelvey', age: 26 }, { name: 'Nikhila Ravi', age: 26 }, { name: 'Kassandra Perch', age: 26 }, { name: 'Michele Garrett', age: 32 }, { name: 'Mariano Vazquez', age: 32 }, { name: 'Athan Reines', age: 42 }, { name: 'Mathias Bynens', age: 54 }]
  47. @koste4 RENDIMIENTO

  48. 48 N I T R O V 8

  49. @koste4 SELF-HOSTING Implementar partes de un lenguaje en ese mismo

    lenguaje
  50. @koste4 PERO… ¿NO ES LENTO? Los arreglos en JS tienen

    metódos cómo
 , , y por supuesto
 
 forEach map reduce sort Todos éstos métodos reciben una 
 función callback como argumento
  51. @koste4 PERO… ¿NO ES LENTO? Iteran sobre una lista e

    invocan la función
 callback para cada elemento La ejecución cambia entre C++ compilado 
 y JS interpretado
  52. @koste4 PERO… ¿NO ES LENTO? El cambio de contexto cuesta

    caro Mantenerse en el mismo contexto de
 ejecución y en el mismo lenguaje 
 permite mejor rendimiento
  53. @koste4 Motor JS Algoritmo de Ordenamiento Self-Host ? SpiderMonkey F

    I R E F O X Insertion Sort (arreglos pequeños)
 Merge Sort No V8 C H R O M E Insertion Sort (arreglos pequeños)
 Quick Sort Sí Nitro S A F A R I Merge Sort Sí Chakra I N T E R N E T E X P L O R E R QuickSort No
  54. @koste4 HORA DE 
 BENCHMARKING

  55. @koste4 10 ELEMENTOS

  56. @koste4 10O ELEMENTOS

  57. @koste4 1,0O0 ELEMENTOS

  58. @koste4 100,00O ELEMENTOS

  59. @koste4 1,000,000 ELEMENTOS

  60. None
  61. @koste4 1,000,000 ELEMENTOS

  62. @koste4 10,000,000 ELEMENTOS

  63. None
  64. @koste4 MÁS SOBRE EL TEMA… The Algorithm Design Manual by

    Steven S. Skiena Foundations of Algorithms by Richard Neapolitan & Kumarss Naimipour
  65. @koste4 MÁS SOBRE EL TEMA… https://www.youtube.com/watch?v=ROalU379l3U

  66. @koste4 https://alistapart.com/article/what-i-talk-about-when-i-talk-about-sorting

  67. @koste4 Gracias Buenos Aires! ! n