🌐 AIæœçŽą & 代理 䞻饔
15 mai 2024

Arrays

Les objets vous permettent de stocker des collections de valeurs Ă  clĂ©. C’est trĂšs bien.

Mais assez souvent, nous trouvons qu’il nous faut une collection ordonnĂ©e, oĂč nous avons un 1er, un 2Ăšme, un 3Ăšme Ă©lĂ©ment, etc. Par exemple, nous avons besoin de cela pour stocker une liste de quelque chose : utilisateurs, trucs, Ă©lĂ©ments HTML, etc.

Il n’est pas pratique d’utiliser un objet ici, car il ne fournit aucune mĂ©thode pour gĂ©rer l’ordre des Ă©lĂ©ments. Nous ne pouvons pas insĂ©rer une nouvelle propriĂ©tĂ© “entre” celles existantes. Les objets ne sont tout simplement pas destinĂ©s Ă  un tel usage.

Il existe une structure de données spéciale appelée Array (tableau), pour stocker les collections ordonnées.

Déclaration

Il existe deux syntaxes pour créer un tableau vide :

let arr = new Array();
let arr = [];

La plupart du temps c’est la deuxiĂšme syntaxe qui est utilisĂ©e. Nous pouvons fournir des Ă©lĂ©ments initiaux entre parenthĂšses :

let fruits = ["Apple", "Orange", "Plum"];

Les éléments de tableau sont numérotés en commençant par zéro.

On peut obtenir un élément par son numéro grace aux crochets :

let fruits = ["Apple", "Orange", "Plum"];

alert( fruits[0] ); // Apple
alert( fruits[1] ); // Orange
alert( fruits[2] ); // Plum

Nous pouvons remplacer un élément :

fruits[2] = 'Pear'; // maintenant ["Apple", "Orange", "Pear"]


Ou en ajouter un nouveau au tableau :

fruits[3] = 'Lemon'; // maintenant ["Apple", "Orange", "Pear", "Lemon"]

Le nombre total d’élĂ©ments dans le tableau est sa length (longueur) :

let fruits = ["Apple", "Orange", "Plum"];

alert( fruits.length ); // 3

Nous pouvons Ă©galement utiliser un alert pour afficher l’ensemble du tableau :

let fruits = ["Apple", "Orange", "Plum"];

alert( fruits ); // Apple,Orange,Plum

Un tableau peut stocker des éléments de tout type.

Par exemple :

// mélange de valeurs
let arr = [ 'Apple', { name: 'John' }, true, function() { alert('hello'); } ];

// récupÚre l'objet à l'index 1 et montre ensuite son nom
alert( arr[1].name ); // John

// affiche la fonction à l'index 3 et l'exécute la
arr[3](); // hello
Trailing comma (virgule de fin)

Un tableau, comme pour un objet, peut se terminer par une virgule :

let fruits = [
  "Apple",
  "Orange",
  "Plum",
];

Le style “virgule de fin” facilite l’insertion et la suppression d’élĂ©ments, car toutes les lignes se ressemblent.

RĂ©cupĂ©rer les derniers Ă©lĂ©ments avec “at”

Un ajout récent
Ceci est un ajout récent au language. Les anciens navigateurs peuvent nécessiter des polyfills.

Disons que nous voulons le dernier élément du tableau.

Certains langages de programmation permettent l’utilisation d’index nĂ©gatifs pour ça, comme fruits[-1].

Tandis qu’en JavaScript ça ne fonctionnera pas. Le rĂ©sultat sera undefined, parce que l’index dans les crochets est traitĂ© littĂ©ralement.

Nous pouvons calculer explicitement l’index du dernier Ă©lĂ©ment et donc y accĂ©der: fruits[fruits.length - 1].

let fruits = ["Apple", "Orange", "Plum"];

alert( fruits[fruits.length-1] ); // Plum

Un peu lourd, n’est-ce pas ? Nous devons Ă©crire le mĂȘme nom de variable deux fois.

Heureusement, il y a une syntaxe plus courte : fruits.at(-1) :

let fruits = ["Apple", "Orange", "Plum"];

// Identique Ă  fruits[fruits.length-1]
alert( fruits.at(-1) ); // Plum

En d’autres termes, arr.at(i):

  • est exactement identique Ă  arr[i], si i >= 0.
  • pour les valeurs nĂ©gatives de i, ça recule depuis la fin du tableau.

Les méthodes pop/push, shift/unshift

Une queue (file d’attente) est l’une des utilisations les plus courantes pour les tableaux. En informatique, cela signifie une collection ordonnĂ©e d’élĂ©ments qui supporte deux opĂ©rations :

  • push ajoute un Ă©lĂ©ment Ă  la fin.
  • shift enlĂšve un Ă©lĂ©ment depuis le dĂ©but, en faisant avancer la file d’attente, de sorte que le deuxiĂšme Ă©lĂ©ment devienne le premier.

Les tableaux prennent en charge les deux opérations.

En pratique, nous en avons besoin trĂšs souvent. Par exemple, une file d’attente de messages devant ĂȘtre affichĂ©s Ă  l’écran.

Il y a un autre cas d’utilisation pour les tableaux – la structure de donnĂ©es nommĂ©e stack.

Il supporte deux opérations :

  • push ajoute un Ă©lĂ©ment Ă  la fin.
  • pop enlĂšve un Ă©lĂ©ment de la fin.

Ainsi, de nouveaux Ă©lĂ©ments sont ajoutĂ©s ou enlevĂ©s toujours Ă  partir de la “fin”.

Un stack (pile) est généralement illustrée par un jeu de cartes. De nouvelles cartes sont ajoutées ou enlevées par le haut :

Pour les stacks (piles), le dernier Ă©lĂ©ment envoyĂ© est reçu en premier, c’est le principe LIFO (Last-In-First-Out, dernier entrĂ©, premier sorti). Pour les files d’attente, nous avons FIFO (First-In-First-Out, premier entrĂ©, premier sorti).

Les tableaux en JavaScript peuvent fonctionner Ă  la fois en queue et en stack. Ils vous permettent d’ajouter ou supprimer des Ă©lĂ©ments Ă  la fois par le dĂ©but ou par la fin.

En informatique, la structure de donnĂ©es qui permet cela s’appelle deque.

Méthodes qui fonctionnent avec la fin du tableau :

pop

Extrait le dernier élément du tableau et le renvoie :

let fruits = ["Apple", "Orange", "Pear"];

alert( fruits.pop() ); // supprime "Pear" et l'alerte

alert( fruits ); // Apple, Orange

Les deux mĂ©thodes fruits.pop() et fruits.at(-1) renvoient le dernier Ă©lĂ©ment du tableau, mais fruits.pop() modifie Ă©galement le tableau en supprimant l’élĂ©ment.

push

Ajoute l’élĂ©ment Ă  la fin du tableau :

let fruits = ["Apple", "Orange"];

fruits.push("Pear");

alert( fruits ); // Apple, Orange, Pear

L’appel de fruits.push(...) est Ă©gal Ă  fruits[fruits.length] = ....

Méthodes qui fonctionnent avec le début du tableau :

shift

Extrait le premier élément du tableau et le renvoie :

let fruits = ["Apple", "Orange", "Pear"];

alert( fruits.shift() ); // supprime "Apple" et l'alerte

alert( fruits ); // Orange, Pear
unshift

Ajoute l’élĂ©ment au dĂ©but du tableau :

let fruits = ["Orange", "Pear"];

fruits.unshift("Apple");

alert( fruits ); // Apple, Orange, Pear

Les méthodes push et unshift peuvent ajouter plusieurs éléments à la fois :

let fruits = ["Apple"];

fruits.push("Orange", "Peach");
fruits.unshift("Pineapple", "Lemon");

// ["Pineapple", "Lemon", "Apple", "Orange", "Peach"]
alert( fruits );

Les internes

Un tableau est un type d’objet spĂ©cial. Les crochets utilisĂ©s pour accĂ©der Ă  la propriĂ©tĂ© arr[0] proviennent en fait de la syntaxe de l’objet. C’est essentiellement la mĂȘme chose que obj[key], oĂč arr est l’objet, tandis que les nombres sont utilisĂ©s comme clĂ©s.

Ils Ă©tendent les objets en fournissant des mĂ©thodes spĂ©ciales pour travailler avec des collections ordonnĂ©es de donnĂ©es ainsi que la propriĂ©tĂ© length. Mais au fond c’est toujours un objet.

N’oubliez pas qu’il n’y a que huit types de base en JavaScript (voir le chapitre Les types de donnĂ©es pour plus d’infos). Array est un objet et se comporte donc comme un objet.

Par exemple, il est copié par référence :

let fruits = ["Banana"]

let arr = fruits; // copier par rĂ©fĂ©rence (deux variables font rĂ©fĂ©rence au mĂȘme tableau)

alert( arr === fruits ); // true

arr.push("Pear"); // modifie le tableau par référence

alert( fruits ); // Banana, Pear - 2 items maintenant


Mais ce qui rend les tableaux vraiment spĂ©ciaux, c’est leur reprĂ©sentation interne. Le moteur tente de stocker ses Ă©lĂ©ments dans une zone de mĂ©moire contiguĂ«, l’un aprĂšs l’autre, exactement comme le montrent les illustrations de ce chapitre. Il existe Ă©galement d’autres optimisations permettant de faire fonctionner les tableaux trĂšs rapidement.

Mais ils se cassent tous si nous arrĂȘtons de travailler avec un tableau comme avec une “collection ordonnĂ©e” et commençons Ă  le travailler comme s’il s’agissait d’un objet normal.

Par exemple, techniquement, nous pouvons faire ceci :

let fruits = []; // créer un tableau

fruits[99999] = 5; // assigne une propriété avec un index beaucoup plus grand que sa longueur

fruits.age = 25; // créer une propriété avec un nom arbitraire

C’est possible, car les tableaux sont des objets Ă  leur base. Nous pouvons leur ajouter des propriĂ©tĂ©s.

Mais le moteur verra que nous travaillons avec le tableau comme avec un objet normal. Les optimisations spécifiques à un tableau ne sont pas adaptées à ce type de situation et seront désactivées. Leurs avantages disparaissent.

Les moyens de casser un tableau :

  • Ajouter une propriĂ©tĂ© non numĂ©rique comme arr.test = 5.
  • Faire des trous, comme ajouter arr[0] et ensuite arr[1000] (et rien entre eux).
  • Remplire le tableau dans l’ordre inverse, comme arr[1000], arr[999] etc.

Veuillez considĂ©rer les tableaux comme des structures spĂ©ciales pour travailler avec les donnĂ©es ordonĂ©es. Ils fournissent des mĂ©thodes spĂ©ciales pour cela. Les tableaux sont soigneusement rĂ©glĂ©s dans les moteurs JavaScript pour fonctionner avec des donnĂ©es ordonnĂ©es contiguĂ«s, veuillez les utiliser de cette maniĂšre. Et si vous avez besoin de clĂ©s arbitraires, il y a de fortes chances pour que vous ayez rĂ©ellement besoin d’un objet rĂ©gulier {}.

Performance

Les méthodes push/pop vont vite, alors que shift/unshift sont lentes.

Pourquoi est-il plus rapide de travailler avec la fin d’un tableau qu’avec son dĂ©but ? Voyons ce qui se passe pendant l’exĂ©cution :

fruits.shift(); // prends 1 élément du début

Il ne suffit pas de prendre l’élĂ©ment avec le nombre 0. D’autres Ă©lĂ©ments doivent Ă©galement ĂȘtre renumĂ©rotĂ©s.

L’opĂ©ration shift doit faire 3 choses :

  1. Supprimer l’élĂ©ment avec l’index 0.
  2. DĂ©placer tous les Ă©lĂ©ments Ă  gauche, les renumĂ©roter de l’index 1 Ă  0, de2 Ă  1, etc.
  3. Mettre à jour la propriété length.

Plus il y a d’élĂ©ments dans le tableau, plus il y faut de temps pour les dĂ©placer, plus il y a d’opĂ©rations en mĂ©moire.

La mĂȘme chose se produit avec unshift. Pour ajouter un Ă©lĂ©ment au dĂ©but du tableau, nous devons d’abord dĂ©placer les Ă©lĂ©ments existants vers la droite, en augmentant leur index.

Et qu’en est-il avec push/pop ? Ils n’ont pas besoin de dĂ©placer quoi que ce soit. Pour extraire un Ă©lĂ©ment de la fin, la mĂ©thode pop nettoie l’index et raccourcit length.

Les actions pour l’opĂ©ration pop :

fruits.pop(); // enleve 1 élément de la fin

La mĂ©thode pop n’a pas besoin de dĂ©placer quoi que ce soit, car les autres Ă©lĂ©ments conservent leurs index. C’est pourquoi c’est extrĂȘmement rapide.

La mĂȘme chose avec la mĂ©thode push.

Boucles

L’une des mĂ©thodes les plus anciennes pour cycler des Ă©lĂ©ments de tableau est la boucle for sur les index :

let arr = ["Apple", "Orange", "Pear"];

for (let i = 0; i < arr.length; i++) {
  alert( arr[i] );
}

Mais pour les tableaux, il existe une autre forme de boucle, for..of :

let fruits = ["Apple", "Orange", "Plum"];

// itÚre sur des éléments de tableau
for (let fruit of fruits) {
  alert( fruit );
}

Le for..of ne donne pas accĂšs au numĂ©ro de l’élĂ©ment actuel, mais Ă  sa valeur, mais dans la plupart des cas, cela suffit. Et c’est plus court.

Techniquement, comme les tableaux sont des objets, il est Ă©galement possible d’utiliser for..in :

let arr = ["Apple", "Orange", "Pear"];

for (let key in arr) {
  alert( arr[key] ); // Apple, Orange, Pear
}

Mais c’est en fait une mauvaise idĂ©e. Il y a des problĂšmes potentiels avec cela :

  1. La boucle for..in itÚre sur toutes les propriétés, pas seulement les propriétés numériques.

    Il existe des objets dits “array-like” dans le navigateur et dans d’autres environnements, qui ressemblent Ă  des tableaux. C’est-Ă -dire qu’ils ont les propriĂ©tĂ©s length et index, mais ils peuvent Ă©galement avoir d’autres propriĂ©tĂ©s et mĂ©thodes non numĂ©riques, dont nous n’avons gĂ©nĂ©ralement pas besoin. La boucle for..in les listera cependant. Donc, si nous devons travailler avec des objets de type tableau, ces propriĂ©tĂ©s “supplĂ©mentaires” peuvent devenir un problĂšme.

  2. La boucle for..in est optimisĂ©e pour les objets gĂ©nĂ©riques, pas pour les tableaux, elle est 10-100 fois plus lente. Bien sĂ»r, c’est encore trĂšs rapide. L’accĂ©lĂ©ration peut n’importer que dans les goulots d’étranglement ou sembler hors de propos. Mais il faut quand mĂȘme ĂȘtre conscient de la diffĂ©rence.

En rÚgle générale, nous ne devrions pas utiliser for..in pour les tableaux.

Un mot à propos de “length”

La propriĂ©tĂ© length est automatiquement mise Ă  jour lorsque nous modifions le tableau. Pour ĂȘtre prĂ©cis, il ne s’agit pas du nombre de valeurs du tableau, mais du plus grand index numĂ©rique plus un.

Par exemple, un seul élément avec un grand index donne une grande longueur :

let fruits = [];
fruits[123] = "Apple";

alert( fruits.length ); // 124

Notez que nous n’utilisons gĂ©nĂ©ralement pas de tableaux de ce type.

Une autre chose intĂ©ressante Ă  propos de la propriĂ©tĂ© length est qu’elle est accessible en Ă©criture.

Si nous l’augmentons manuellement, rien d’intĂ©ressant ne se produit. Mais si nous le diminuons, le tableau est tronquĂ©. Le processus est irrĂ©versible, voici l’exemple :

let arr = [1, 2, 3, 4, 5];

arr.length = 2; // tronque à 2 éléments
alert( arr ); // [1, 2]

arr.length = 5; // retourne la length d'origine
alert( arr[3] ); // undefined: les valeurs ne reviennent pas

Ainsi, le moyen le plus simple pour effacer le tableau est arr.length = 0;.

new Array()

Il y a une syntaxe supplémentaire pour créer un tableau :

let arr = new Array("Apple", "Pear", "etc");

Il est rarement utilisé, car les crochets [] sont plus courts. En outre, il comporte une caractéristique délicate.

Si new Array est appelé avec un seul argument qui est un nombre, il crée un tableau sans éléments, mais avec la longueur donnée.

Voyons comment on peut se tirer une balle dans le pied :

let arr = new Array(2); // va-t-il créer un tableau de [2] ?

alert( arr[0] ); // undefined! pas d'éléments.

alert( arr.length ); // length 2

Pour éviter de telles surprises, nous utilisons généralement des crochets, sauf si nous savons vraiment ce que nous faisons.

Tableaux multidimensionnels

Les tableaux peuvent avoir des Ă©lĂ©ments qui sont aussi des tableaux. On peut l’utiliser pour des tableaux multidimensionnels, pour stocker des matrices :

let matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];

alert( matrix[1][1] ); // 5, l'élément central

toString

Les tableaux ont leur propre implĂ©mentation de la mĂ©thode toString qui renvoie une liste d’élĂ©ments sĂ©parĂ©s par des virgules.

Par exemple :

let arr = [1, 2, 3];

alert( arr ); // 1,2,3
alert( String(arr) === '1,2,3' ); // true

Aussi, essayons ceci :

alert( [] + 1 ); // "1"
alert( [1] + 1 ); // "11"
alert( [1,2] + 1 ); // "1,21"

Les tableaux n’ont pas de Symbol.toPrimitive, ni de valueOf viable, ils implĂ©mentent uniquement la conversion toString, donc ici [] devient une chaĂźne vide, [1] devient "1" et [1,2] devient "1,2".

Lorsque l’opĂ©rateur binaire plus + ajoute quelque chose Ă  une chaĂźne, il la convertit Ă©galement en chaĂźne, de sorte que l’étape suivante se prĂ©sente comme suit :

alert( "" + 1 ); // "1"
alert( "1" + 1 ); // "11"
alert( "1,2" + 1 ); // "1,21"

Ne comparez pas les tableaux avec ==

Les tableaux en JavaScript, contrairement Ă  certains autres langages de programmation, ne doivent pas ĂȘtre comparĂ©s avec l’opĂ©rateur ==.

Cet opĂ©rateur n’a pas de traitement spĂ©cial pour les tableaux, il fonctionne avec eux comme avec n’importe quel objet.

Rappelons les rĂšgles :

  • Deux objets sont Ă©gaux == uniquement s’ils font rĂ©fĂ©rence au mĂȘme objet.
  • Si l’un des arguments de == est un objet, et l’autre est une primitive, alors l’objet est converti en primitif, comme expliquĂ© dans le chapitre Conversion d'objet en primitive.
  • 
À l’exception de null et undefined qui s’égalent == l’un l’autre et rien d’autre.

La comparaison stricte === est encore plus simple, car elle ne convertit pas les types.

Donc, si nous comparons des tableaux avec ==, ils ne sont jamais les mĂȘmes, sauf si nous comparons deux variables qui rĂ©fĂ©rencent exactement le mĂȘme tableau.

Par exemple :

alert( [] == [] ); // false
alert( [0] == [0] ); // false

Ces tableaux sont des objets techniquement diffĂ©rents. Donc, ils ne sont pas Ă©gaux. L’opĂ©rateur == ne fait pas de comparaison Ă©lĂ©ment par Ă©lĂ©ment.

La comparaison avec les primitives peut également donner des résultats apparemment étranges :

alert( 0 == [] ); // true

alert('0' == [] ); // false

Ici, dans les deux cas, nous comparons une primitive Ă  un objet tableau. Ainsi, le tableau [] est converti en primitive Ă  des fins de comparaison et devient une chaĂźne vide ''.

Ensuite, le processus de comparaison se poursuit avec les primitives, comme décrit dans le chapitre Les conversions de types :

// aprĂšs que [] soit converti vers ''
alert( 0 == '' ); // true, car '' est converti en nombre 0

alert('0' == '' ); // false, pas de conversion de type, différentes chaßnes de caractÚres

Alors, comment comparer des tableaux ?

C’est simple, n’utilisez pas l’opĂ©rateur ==. Au lieu de cela, comparez-les Ă©lĂ©ment par Ă©lĂ©ment dans une boucle ou en utilisant les mĂ©thodes d’itĂ©ration expliquĂ©es dans le chapitre suivant.

Résumé

Array est un type d’objet spĂ©cial, adaptĂ© au stockage et Ă  la gestion des Ă©lĂ©ments de donnĂ©es ordonnĂ©es.

  • La dĂ©claration :

    // crochets (habituel)
    let arr = [item1, item2...];
    
    // new Array (exceptionnellement rare)
    let arr = new Array(item1, item2...);

    L’appel de new Array(number) crĂ©e un tableau de longueur donnĂ©e, mais sans Ă©lĂ©ments.

  • La propriĂ©tĂ© length est la longueur du tableau ou, plus prĂ©cisĂ©ment, son dernier index numĂ©rique plus un. Il est auto-ajustĂ© par les mĂ©thodes de tableau.

  • Si nous raccourcissons length manuellement, le tableau est tronquĂ©.

Obtenir les éléments :

  • nous pouvons obtenir un Ă©lĂ©ment par son index, comme arr[0]
  • nous pouvons Ă©galement utiliser la mĂ©thode at(i) qui autorise les index nĂ©gatifs. Pour les valeurs nĂ©gatives de i, il recule Ă  partir de la fin du tableau. Si i >= 0, cela fonctionne comme arr[i].

Nous pouvons utiliser un tableau comme deque avec les opérations suivantes :

  • push(...items) ajoute items Ă  la fin.
  • pop() supprime l’élĂ©ment de la fin et le renvoie.
  • shift() supprime l’élĂ©ment du dĂ©but et le renvoie.
  • unshift(... items) ajoute des items au dĂ©but.

Pour boucler sur les éléments du tableau :

  • for (let i = 0; i <arr.length; i++) – fonctionne le plus rapidement, compatible avec les anciens navigateurs.
  • for (let item of arr) – la syntaxe moderne pour les Ă©lĂ©ments uniquement.
  • pour (let i in arr) – ne jamais utiliser.

Pour comparer des tableaux, n’utilisez pas l’opĂ©rateur == (ainsi que >, < et autres), car ils n’ont pas de traitement spĂ©cial pour les tableaux. Ils les traitent comme n’importe quel objet, et ce n’est pas ce que nous voulons habituellement.

A la place, vous pouvez utiliser la boucle for..of pour comparer les tableaux élément par élément.

Nous continuerons avec les tableaux et Ă©tudierons d’autres mĂ©thodes pour ajouter, supprimer, extraire des Ă©lĂ©ments et trier des tableaux dans le prochain chapitre MĂ©thodes de tableau.

Exercices

importance: 3

Qu’est-ce que ce code va montrer ?

let fruits = ["Apples", "Pear", "Orange"];

// pousser une nouvelle valeur dans la "copie"
let shoppingCart = fruits;
shoppingCart.push("Banana");

// Qu'y a-t-il dans fruits ?
alert( fruits.length ); // ?

Le résultat est 4 :

let fruits = ["Apples", "Pear", "Orange"];

let shoppingCart = fruits;

shoppingCart.push("Banana");

alert( fruits.length ); // 4

C’est parce que les tableaux sont des objets. Donc, shoppingCart et fruits sont les rĂ©fĂ©rences du mĂȘme tableau.

importance: 5

Essayons 5 opérations de tableau.

  1. CrĂ©ez un tableau styles avec les Ă©lĂ©ments “Jazz” et “Blues”.
  2. Ajoutez “Rock-n-Roll” à la fin.
  3. Remplacez la valeur au milieu par “Classiques”. Votre code pour trouver la valeur moyenne devrait fonctionner pour tous les tableaux de longueur impaire.
  4. Extrayez la premiĂšre valeur du tableau et affichez-la.
  5. Ajoutez Rap et Reggae au tableau.

Le processus du tableau :

Jazz, Blues
Jazz, Blues, Rock-n-Roll
Jazz, Classics, Rock-n-Roll
Classics, Rock-n-Roll
Rap, Reggae, Classics, Rock-n-Roll
let styles = ["Jazz", "Blues"];
styles.push("Rock-n-Roll");
styles[Math.floor((styles.length - 1) / 2)] = "Classics";
alert( styles.shift() );
styles.unshift("Rap", "Reggae");
importance: 5

Quel est le résultat ? Et pourquoi ?

let arr = ["a", "b"];

arr.push(function() {
  alert( this );
});

arr[2](); // ?

L’appel de arr[2]() est syntaxiquement le bon vieux obj[method](), dans le rîle de obj on a arr, et dans le rîle de method on a 2.

Nous avons donc un appel de la fonction arr[2] comme mĂ©thode d’objet. Naturellement, il reçoit this en rĂ©fĂ©rençant l’objet arr et sort le tableau :

let arr = ["a", "b"];

arr.push(function() {
  alert( this );
})

arr[2](); // a,b,function(){...}

Le tableau a 3 valeurs. Il en avait initialement deux, plus la fonction.

importance: 4

Écrivez la fonction sumInput() qui :

  • Demande Ă  l’utilisateur des valeurs utilisant prompt et stocke les valeurs dans le tableau.
  • Finit de demander lorsque l’utilisateur entre une valeur non numĂ©rique, une chaĂźne vide ou appuie sur “Annuler”.
  • Calcule et retourne la somme des Ă©lĂ©ments du tableau.

P.S. Un zĂ©ro 0 est un nombre valide, donc s’il vous plaĂźt n’arrĂȘtez pas l’entrĂ©e sur zĂ©ro.

Exécuter la démo

Veuillez noter le dĂ©tail subtile mais important de la solution. Nous ne convertissons pas instantanĂ©ment value en nombre aprĂšs le prompt, parce qu’aprĂšs value = +value nous ne pourrions pas distinguer une chaĂźne vide (signe d’arrĂȘt) du zĂ©ro (nombre valide). Nous le faisons plus tard Ă  la place.

function sumInput() {

  let numbers = [];

  while (true) {

    let value = prompt("A number please?", 0);

    // devrions-nous annuler ?
    if (value === "" || value === null || !isFinite(value)) break;

    numbers.push(+value);
  }

  let sum = 0;
  for (let number of numbers) {
    sum += number;
  }
  return sum;
}

alert( sumInput() );
importance: 2

L’entrĂ©e est un tableau de nombres, par exemple arr = [1, -2, 3, 4, -9, 6].

La tĂąche est la suivante : trouver le sous-tableau contigu de arr avec la somme maximale des items.

Écrire la fonction getMaxSubSum(arr) qui retournera cette somme.

Par exemple :

getMaxSubSum([-1, 2, 3, -9]) == 5 (la somme des éléments en surbrillance)
getMaxSubSum([2, -1, 2, 3, -9]) == 6
getMaxSubSum([-1, 2, 3, -9, 11]) == 11
getMaxSubSum([-2, -1, 1, 2]) == 3
getMaxSubSum([100, -9, 2, -3, 5]) == 100
getMaxSubSum([1, 2, 3]) == 6 (prend tout)

Si tous les Ă©lĂ©ments sont nĂ©gatifs, cela signifie que nous n’en prenons aucun (le sous-tableau est vide), la somme est donc zĂ©ro :

getMaxSubSum([-1, -2, -3]) = 0

S’il vous plaĂźt essayez de penser Ă  une solution rapide : O(n2) ou mĂȘme Ă  O(n) si vous le pouvez.

Open a sandbox with tests.

Solution lente

Nous pouvons calculer tous les subsums possibles.

Le moyen le plus simple consiste à prendre chaque élément et à calculer les sommes de tous les sous-tableaux à partir de celui-ci.

Par exemple, pour [-1, 2, 3, -9, 11] :

// Commence Ă  -1 :
-1
-1 + 2
-1 + 2 + 3
-1 + 2 + 3 + (-9)
-1 + 2 + 3 + (-9) + 11

// Commence Ă  2 :
2
2 + 3
2 + 3 + (-9)
2 + 3 + (-9) + 11

// Commence Ă  3 :
3
3 + (-9)
3 + (-9) + 11

// Commence Ă  -9 :
-9
-9 + 11

// Commence Ă  11 :
11

Le code est en rĂ©alitĂ© une boucle imbriquĂ©e : la boucle externe recouvrant les Ă©lĂ©ments du tableau, et l’interne compte les sous-sommes commençant par l’élĂ©ment en cours.

function getMaxSubSum(arr) {
  let maxSum = 0; // si on ne prend aucun élément, zéro sera retourné

  for (let i = 0; i < arr.length; i++) {
    let sumFixedStart = 0;
    for (let j = i; j < arr.length; j++) {
      sumFixedStart += arr[j];
      maxSum = Math.max(maxSum, sumFixedStart);
    }
  }

  return maxSum;
}

alert( getMaxSubSum([-1, 2, 3, -9]) ); // 5
alert( getMaxSubSum([-1, 2, 3, -9, 11]) ); // 11
alert( getMaxSubSum([-2, -1, 1, 2]) ); // 3
alert( getMaxSubSum([1, 2, 3]) ); // 6
alert( getMaxSubSum([100, -9, 2, -3, 5]) ); // 100

La solution a une complexitĂ© temporelle de O(n2). En d’autres termes, si nous augmentons la taille du tableau 2 fois, l’algorithme fonctionnera 4 fois plus longtemps.

Pour les grands tableaux (1’000, 10’000 Ă©lĂ©ments ou plus), de tels algorithmes peuvent conduire Ă  une grande lenteur.

Solution rapide

Parcourons le tableau et conservons la somme partielle actuelle des éléments dans la variable s. Si s devient négatif à un moment donné, assignez s=0. Le maximum de tous ces s sera la réponse.

Si la description est trop vague, veuillez voir le code, il est assez court :

function getMaxSubSum(arr) {
  let maxSum = 0;
  let partialSum = 0;

  for (let item of arr) { // pour chaque élément d'arr
    partialSum += item; // l'ajouter Ă  partialSum
    maxSum = Math.max(maxSum, partialSum); // mémorise le maximum
    if (partialSum < 0) partialSum = 0; // zéro si négatif
  }

  return maxSum;
}

alert( getMaxSubSum([-1, 2, 3, -9]) ); // 5
alert( getMaxSubSum([-1, 2, 3, -9, 11]) ); // 11
alert( getMaxSubSum([-2, -1, 1, 2]) ); // 3
alert( getMaxSubSum([100, -9, 2, -3, 5]) ); // 100
alert( getMaxSubSum([1, 2, 3]) ); // 6
alert( getMaxSubSum([-1, -2, -3]) ); // 0

L’algorithme nĂ©cessite exactement 1 passage de tableau, la complexitĂ© temporelle est donc O(n).

Vous pouvez trouver plus d’informations dĂ©taillĂ©es sur l’algorithme ici : Maximum subarray problem. Si la raison de ce fonctionnement n’est pas encore Ă©vidente, tracez l’algorithme Ă  partir des exemples ci-dessus et voyez comment il fonctionne.

Ouvrez la solution avec des tests dans une sandbox.

Carte du tutoriel

Commentaires

lire ceci avant de commenter

  • Si vous avez des amĂ©liorations Ă  suggĂ©rer, merci de soumettre une issue GitHub ou une pull request au lieu de commenter.
  • Si vous ne comprenez pas quelque chose dans l'article, merci de prĂ©ciser.
  • Pour insĂ©rer quelques bouts de code, utilisez la balise <code>, pour plusieurs lignes – enveloppez-les avec la balise <pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepen
)