Level up je .soort spel

0
23

Het sorteren is een super handige JavaScript-methode dat kan de weergave van de waarden van een matrix in een bepaalde volgorde. Of dat de onroerend goed listings door de prijs, de burger gewrichten door afstand, of de beste in de buurt happy hours door waardering, arrays sorteren van de informatie is een gemeenschappelijke behoefte.

Als u al bent om dit te doen met JavaScript op een project, je zal waarschijnlijk met behulp van de ingebouwde array .sorteer methode, die in dezelfde familie van de array methoden omvat .- filter .kaart en .verminderen.

Laten we een kijkje nemen hoe dat te doen!

Een korte opmerking over bijwerkingen

Alvorens in te gaan op de details van hoe het te gebruiken .soort, er is een zeer belangrijk detail is dat aangepakt dient te worden. Terwijl veel van de ES5 array methoden, zoals .- filter .kaart, en .verminderen zal terug een nieuwe array aan en laat de oorspronkelijke, onbewerkte, .sorteren zal sorteer de array in de plaats. Als dit ongewenst is, een ES6 techniek om dit te voorkomen is het gebruik van de verspreiding van de operator om het kort en bondig maken van een nieuwe array.

const foo = [‘c’,’b’,’a’];
const bar = [‘x’,’z’,’y’];
const fooSorted = foo.sorteer();
const barSorted = […bar].sorteer();

console.log({foo, fooSorted, bar, barSorted});

/*
{
“foo”: [ “a”, “b”, “c” ],
“fooSorted”: [ “a”, “b”, “c” ],
“bar”: [ “x”, “z”, “y” ],
“barSorted”: [ “x”, “y”, “z” ]
}
*/

foo en fooSorted beide verwijzen naar dezelfde array, maar de bar en het barSorted zijn nu afzonderlijke matrices.

Algemeen overzicht

De enige parameter van de .sorteer methode is een functie. De spec noemt dit de compareFn — ik zal verwijzen als de “vergelijking” functie voor de rest van de post. Deze vergelijking functie accepteert twee parameters, die ik zal aanduiden als a en b. a en b zijn de twee elementen die we vergelijken. Als u niet geven een vergelijking van de functie, de array zal dwingen elk element in een string en sorteren volgens de Unicode-punten.

Als je een besteld worden, de eerste in de array, de vergelijking van de functie moet terug een negatief geheel getal; voor b, een positief geheel getal zijn. Als u wilt de twee om het behouden van hun huidige bestelling, het retourneren 0.

Als je het niet begrijpt, maak je geen zorgen! Hopelijk zal veel meer duidelijk met een paar voorbeelden.

Het vergelijken van getallen

Een van de eenvoudigste callbacks te schrijven is een aantal vergelijking.

const getallen = [13,8,2,21,5,1,3,1];
const byValue = (a,b) => a – b;
const gesorteerd = […nummers].sorteren(byValue);
console.log(gesorteerd); // [1,1,2,3,5,8,13,21]

Als a groter is dan b, a – b zal u een positief getal, dus b wordt eerst gesorteerd.

Het vergelijken van tekenreeksen

Bij het vergelijken van tekenreeksen, de > en < operators vergelijken de waarden gebaseerd zijn op elke tekenreeks die de Unicode-waarde. Dit betekent dat alle hoofdletters worden “minder” dan de kleine letters, die kan leiden tot onverwacht gedrag.

JavaScript is een methode om te helpen met het vergelijken van tekenreeksen: de String.prototype.localeCompare methode. Deze methode accepteert een vergelijking string, van een locale, en een van de opties object. De opties object accepteert een paar eigenschappen (die u allemaal kunt bekijken hier), maar ik vind dat het meest nuttig is “gevoeligheid.” Dit zal invloed hebben op hoe vergelijkingen werk tussen de letter-variaties zoals het geval en accent.

const strings = [‘Über’, ‘alpha’, ‘Ijver’, ‘über’, ‘uber’, ‘Uber’, ‘Alpha’, ‘ijver’];

const sortBySensitivity = gevoeligheid => (a, b) => een.localeCompare(
b,
undefined // locale string — undefined betekent het gebruiken van de browser standaard
{ gevoeligheid }
);

const byAccent = sortBySensitivity(‘accent’);
const byBase = sortBySensitivity(‘basis’);
const byCase = sortBySensitivity(‘geval’);
const byVariant = sortBySensitivity(‘variant’); // standaard

const accentSorted = […strings].sorteren(byAccent);
const baseSorted = […strings].sorteren(byBase);
const caseSorted = […strings].sorteren(byCase);
const variantSorted = […strings].sorteren(byVariant);

console.log({accentSorted, baseSorted, caseSorted, variantSorted});

/*
{
“accentSorted”: [ “alpha”, “Alpha”, “uber”, “Uber”, “Über”, “über”, “Vuur”, “ijver” ],
“baseSorted”: [ “alpha”, “Alpha”, “Über”, “über”, “uber”, “Uber”, “Vuur”, “ijver” ],
“caseSorted”: [ “alpha”, “Alpha”, “über”, “uber”, “Über”, “Uber”, “vuur”, “Ijver” ],
“variantSorted”: [ “alpha”, “Alpha”, “uber”, “Uber”, “über”, “Über”, “vuur”, “Ijver” ]
}
*/

Voor mij, baseSorted lijkt de meest logische voor de meeste alfabetische sortering — ‘ü’, ‘u’, ‘Ü’, en ‘U’ zijn gelijkwaardig, dus blijven ze in de volgorde van de originele matrix.

Uitvoeren van functies voor het vergelijken van waarden

U wilt voor het uitvoeren van een vergelijking van de functie een waarde die is afgeleid van elk array-element. Eerste, laten we het schrijven van een vergelijking van de functie fabriek die “kaart” over het element voor het aanroepen van de functie ter vergelijking.

const sortByMapped = (kaart,compareFn) => (a,b) => compareFn(kaart van(een) kaart(b));

Een use case voor dit is te sorteren op basis van het kenmerk van een object.

const aankopen = [
{ name: ‘Popcorn’, prijs: 5.75 },
{ name: ‘Film’, prijs: 12 },
{ name: ‘Soda’, prijs: 3.75 },
{ name: ‘Candy’, prijs: 5 },
];

const sortByMapped = (kaart,compareFn) => (a,b) => compareFn(kaart van(een) kaart(b));
const byValue = (a,b) => a – b;
const toPrice = e => e.prijs;
const byPrice = sortByMapped(toPrice,byValue);

console.log([…aankopen].sorteren(byPrice));

/*
[
{ naam: “Soda”, prijs: 3.75 },
{ naam: “Candy”, prijs: 5 },
{ naam: “Popcorn”, prijs: 5.75 },
{ naam: “Kaartje”, prijs: 12 }
]
*/

Een ander geval zou kunnen zijn om te vergelijken met een reeks van data.

const data = [‘2018-12-10’, ‘1991-02-10’, ‘2015-10-07’, ‘1990-01-11’];
const sortByMapped = (kaart,compareFn) => (a,b) => compareFn(kaart van(een) kaart(b));
const toDate = e => new Date(e).getTime();
const byValue = (a,b) => a – b;
const byDate = sortByMapped(to date,byValue);

console.log([…data].sorteren(byDate));
// [“1990-01-11”, “1991-02-10”, “2015-10-07”, “2018-12-10”]

Het omkeren van een soort

Er zijn enkele gevallen waarin u wilt omkeren van de uitkomst van een vergelijking van de functie. Dit is enigszins anders dan het doen van een soort en dan het omkeren van het resultaat in de weg banden worden behandeld: als je achteruit de uitkomst, banden zullen ook worden omgekeerd in orde is.

Voor het schrijven van een hogere-orde functie accepteert een vergelijking van de functie en geeft een nieuwe, moet u de flip-in het teken van de vergelijking van de retourwaarde.

const flipComparison = fn => (a,b) => -fn(a,b);
const byAlpha = (a,b) => een.localeCompare(b, null, { gevoeligheid: ‘base’ });
const byReverseAlpha = flipComparison(byAlpha);

console.log([‘A’, ‘B’, ‘C’].sorteren(byReverseAlpha)); // [‘C’,’B’,’A’]

Het runnen van een tiebreak soort

Er zijn tijden wanneer u wilt hebben van een “tie-breaker” sort — dat is, is een andere vergelijking van de functie die wordt gebruikt in het geval van een gelijkspel.

Met behulp van [].verminderen, kunt u plat een array van vergelijking functies in één.

const sortByMapped = map => compareFn => (a,b) => compareFn(kaart van(een) kaart(b));
const flipComparison = fn => (a,b) => -fn(a,b);
const byValue = (a,b) => a – b;

const byPrice = sortByMapped(e => e.de prijs)(byValue);
const byRating = sortByMapped(e => e.waardering)(flipComparison(byValue));

const sortByFlattened = fns => (a,b) =>
fns.verminderen((acc, fn) => acc || fn(a,b), 0);

const byPriceRating = sortByFlattened([byPrice,byRating]);

const restaurants = [
{ naam: “Foo’ s Burger Stand”, prijs: 1, rating: 3 },
{ naam: “De Tapas Bar”, prijs: 3, rating: 4 },
{ naam: “Baz Pizza”, prijs: 3, rating: 2 },
{ naam: “Geweldige Deal”, prijs: 1, rating: 5 },
{ naam: “te Duur”, prijs: 5, rating: 1 },
];

console.log(restaurants.sorteren(byPriceRating));

/*
{naam: “Geweldige Deal”, prijs: 1, rating: 5}
{naam: “Foo’ s Burger Stand”, prijs: 1, rating: 3}
{naam: “De Tapas Bar”, prijs: 3, rating: 4}
{naam: “Baz Pizza”, prijs: 3, rating: 2}
{naam: “te Duur”, prijs: 5, rating: 1}
*/

Het schrijven van een willekeurige soort

Wilt u misschien om te sorteren van een array “willekeurig.” Een techniek die ik heb gezien is aan de volgende functie gebruiken als de vergelijking van de functie.

const byRandom = () => Math.random() – .5;

Sinds Wiskunde.random() retourneert een “willekeurig” getal tussen 0 en 1, de byRandom functie moet terug een positief getal is de helft van de tijd en een negatief getal is de andere helft. Dit lijkt een goede oplossing zou zijn, maar helaas, sinds de vergelijking functie is niet “in lijn” — wat betekent dat het niet dezelfde waarde als meerdere keren met dezelfde waarden, kan leiden tot onverwachte resultaten.

Voor het voorbeeld nemen we een array van getallen tussen 0 en 4. Als dit byRandom functie was echt willekeurig is, zou verwacht kunnen worden dat de nieuwe index van elk nummer zou worden verspreid gelijkmatig over voldoende iteraties. De oorspronkelijke waarde 0 zou net zoveel kans om in de index-4 index 0 in de nieuwe matrix. In de praktijk blijkt echter, deze functie zal bias elk nummer naar zijn oorspronkelijke positie.

Zie de Pen
Array.sort() Willekeurige 👎 door Adam Giese (@AdamGiese)
op CodePen.

De “diagonaal” van de top-links zal statistisch gezien de grootste waarde. In een ideaal en werkelijk willekeurige soort, elke cel in de tabel zou zweven rond de 20%.

De oplossing hiervoor is om een manier te vinden om ervoor te zorgen dat de vergelijking van de functie consistent blijft. Een manier om dit te doen is het in kaart brengen van de willekeurige waarde voor elk array-element voor de vergelijking, dan is de kaart te lopen na.

const sortByMapped = map => compareFn => (a,b) => compareFn(kaart van(een) kaart(b));
const values = [0,1,2,3,4,5,6,7,8,9];
const withRandom = (e) => ({ random: Math.random(), originele: e });
const toOriginal = ({oorspronkelijke}) => oorspronkelijk;
const toRandom = ({random}) => willekeurige volgorde;
const byValue = (a,b) => a – b;
const byRandom = sortByMapped(toRandom)(byValue);

const shuffleArray = array => array
.kaart(withRandom)
.sorteren(byRandom)
.kaart(toOriginal);

Dit zorgt ervoor dat elk element heeft een enkele willekeurige waarde wordt slechts eenmaal per element in plaats van een keer per vergelijking. Dit verwijdert het sorteren van bias in de richting van de oorspronkelijke positie.

Zie de Pen
Array.sort() Willekeurige 👍 door Adam Giese (@AdamGiese)
op CodePen.