J'ai du mal à trouver comment déplacer un élément de tableau. Par exemple, compte tenu des éléments suivants:
var arr = [ 'a', 'b', 'c', 'd', 'e'];
Comment puis-je écrire une fonction à déplacer 'd'
auparavant 'b'
?
Ou 'a'
après 'c'
?
Après le déplacement, les indices du reste des éléments doivent être mis à jour. Cela signifie que dans le premier exemple après le déplacement arr [0] serait = 'a', arr [1] = 'd' arr [2] = 'b', arr [3] = 'c', arr [4] = «e»
Cela semble être assez simple, mais je ne peux pas envelopper ma tête.
javascript
arrays
Mark Brown
la source
la source
const changeValuePosition = (arr, init, target) => {[arr[init],arr[target]] = [arr[target],arr[init]]; return arr}
init
ettarget
.Réponses:
Si vous souhaitez une version sur npm, array-move est le plus proche de cette réponse, bien que ce ne soit pas la même implémentation. Voir sa section d'utilisation pour plus de détails. La version précédente de cette réponse (qui a modifié Array.prototype.move) peut être trouvée sur npm à array.prototype.move .
J'ai eu un assez bon succès avec cette fonction:
Notez que le dernier
return
est simplement à des fins de test:splice
effectue des opérations sur le tableau sur place, donc un retour n'est pas nécessaire. Par extension, ilmove
s'agit d'une opération sur place. Si vous voulez éviter cela et renvoyer une copie, utilisezslice
.Parcourir le code:
new_index
est supérieur à la longueur du tableau, nous voulons (je présume) remplir correctement le tableau avec de nouveauxundefined
s. Ce petit extrait gère cela en poussantundefined
sur le tableau jusqu'à ce que nous ayons la bonne longueur.arr.splice(old_index, 1)[0]
intérieur, nous épissons l'ancien élément.splice
renvoie l'élément qui a été épissé, mais il est dans un tableau. Dans notre exemple ci-dessus, c'était[1]
. Nous prenons donc le premier index de ce tableau pour y obtenir le brut1
.splice
pour insérer cet élément à la place de new_index. Puisque nous avons complété le tableau ci-dessusnew_index > arr.length
, il apparaîtra probablement au bon endroit, à moins qu'ils n'aient fait quelque chose d'étrange comme passer dans un nombre négatif.Une version plus sophistiquée pour tenir compte des indices négatifs:
Ce qui devrait expliquer des choses comme
array_move([1, 2, 3], -1, -2)
correctement (déplacer le dernier élément à l'avant-dernier endroit). Le résultat devrait être[1, 3, 2]
.De toute façon, dans votre question d'origine, vous feriez
array_move(arr, 0, 2)
poura
aprèsc
. Pourd
avantb
, vous le feriezarray_move(arr, 3, 1)
.la source
.hasOwnProperty
vérification lors de l'itération avec des choses comme for..in, en particulier avec des bibliothèques comme Prototype et MooTools qui modifient les prototypes. Quoi qu'il en soit, je ne pensais pas que c'était un problème particulièrement important dans un exemple relativement limité comme celui-ci, et il y a une belle division dans la communauté sur la question de savoir si la modification du prototype est une bonne idée. Normalement, les problèmes d'itération sont cependant les moins préoccupants.this[new_index] = undefined;
dans leif
bloc. Comme les tableaux Javascript sont rares, cela étendra la taille du tableau pour inclure le new_index pour que le.splice
travail fonctionne, mais sans avoir besoin de créer des éléments intermédiaires.this[new_index] = undefined
mettra en fait unundefined
dans le slot du tableau avant l'index correct. (Par exemple, il[1,2,3].move(0,10)
y aura1
dans l'emplacement 10 etundefined
dans l'emplacement 9.) Au contraire, si la parcimonie est correcte, nous pourrions nousthis[new_index] = this.splice(old_index, 1)[0]
passer de l'autre appel d'épissage (en faire un if / else à la place).Voici un liner que j'ai trouvé sur JSPerf ....
ce qui est génial à lire, mais si vous voulez des performances (dans de petits ensembles de données) essayez ...
Je ne peux pas prendre de crédit, tout devrait revenir à Richard Scarrott . Il bat la méthode basée sur l'épissure pour les petits ensembles de données dans ce test de performance . Il est cependant beaucoup plus lent sur des ensembles de données plus volumineux, comme le souligne Darwayne .
la source
from >= to ? this.splice(to, 0, this.splice(from, 1)[0]) : this.splice(to - 1, 0, this.splice(from, 1)[0]);
J'aime cette façon. C'est concis et ça marche.
Remarque: n'oubliez pas de vérifier les limites de votre tableau.
Exécutez l'extrait de code sur jsFiddle
la source
comme la fonction est chaînable, cela fonctionne aussi:
démo ici
la source
Mon 2c. Facile à lire, il fonctionne, il est rapide, il ne crée pas de nouveaux tableaux.
la source
array
, comme cela a été fait à la fin.J'ai eu l'idée de @Reid de pousser quelque chose à la place de l'élément qui est censé être déplacé pour garder la taille du tableau constante. Cela simplifie les calculs. De plus, pousser un objet vide a l'avantage supplémentaire de pouvoir le rechercher uniquement plus tard. Cela fonctionne car deux objets ne sont pas égaux jusqu'à ce qu'ils se réfèrent au même objet.
Voici donc la fonction qui prend dans le tableau source, et la source, les index de destination. Vous pouvez l'ajouter au Array.prototype si nécessaire.
la source
sourceIndex = 0
,destIndex = 1
destIndex
est censé être l'index avant que l'élément source ne soit déplacé dans le tableau.Ceci est basé sur la solution de @ Reid. Sauf:
Array
prototype.undefined
éléments, il déplace simplement l'élément vers la position la plus à droite.Une fonction:
Tests unitaires:
la source
Voici ma solution one liner ES6 avec un paramètre optionnel
on
.Adaptation de la première solution proposée par
digiguru
Le paramètre
on
est le nombre d'élément à partir duquelfrom
vous souhaitez vous déplacer.la source
La
splice
méthode deArray
pourrait aider: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/spliceGardez à l'esprit qu'il peut être relativement coûteux car il doit réindexer activement le tableau.
la source
Une approche serait de créer un nouveau tableau avec les pièces dans l'ordre que vous souhaitez, en utilisant la méthode de tranche.
Exemple
la source
arr2
finissez par être une chaîne en raison des opérations de concaténation, non? :) Cela finit par être"adc,de"
.Vous pouvez implémenter un calcul de base et créer une fonction universelle pour déplacer l'élément de tableau d'une position à l'autre.
Pour JavaScript, cela ressemble à ceci:
Consultez les "éléments du tableau en mouvement" sur "gloommatter" pour une explication détaillée.
http://www.gloommatter.com/DDesign/programming/moving-any-array-elements-universal-function.html
la source
J'ai implémenté une
ECMAScript 6
solution immuable basée sur@Merc
la réponse de ici:Les noms de variables peuvent être raccourcis, il suffit d'utiliser des noms longs pour que le code puisse s'expliquer.
la source
array
immédiatement sifromIndex === toIndex
et ne créer lenewArray
si ce n'est pas le cas? L'immuabilité ne signifie pas qu'une nouvelle copie doit être créée par appel de fonction, même en l'absence de changement. Le simple fait de demander à b / c le motif de l'augmentation de la longueur de cette fonction (par rapport aux lignes isolées basées sur les épissures) est la performance, etfromIndex
peut souvent être égaltoIndex
, en fonction de l'utilisation.J'avais besoin d'une méthode de déplacement immuable (qui ne modifiait pas le tableau d'origine), j'ai donc adapté la réponse acceptée de @ Reid pour simplement utiliser Object.assign pour créer une copie du tableau avant de faire l'épissure.
Voici un jsfiddle le montrant en action .
la source
http://plnkr.co/edit/JaiAaO7FQcdPGPY6G337?p=preview
la source
J'ai fini par combiner deux d'entre eux pour travailler un peu mieux lors de déplacements sur de petites et grandes distances. J'obtiens des résultats assez cohérents, mais cela pourrait probablement être modifié un peu par quelqu'un de plus intelligent que moi pour travailler différemment pour différentes tailles, etc.
Utiliser certaines des autres méthodes pour déplacer des objets sur de petites distances était beaucoup plus rapide (x10) que d'utiliser une épissure. Cela peut changer en fonction de la longueur des tableaux, mais c'est vrai pour les grands tableaux.
http://jsperf.com/arraymove-many-sizes
la source
Il est dit à de nombreux endroits ( ajouter des fonctions personnalisées dans Array.prototype ) que jouer avec le prototype Array pourrait être une mauvaise idée, de toute façon j'ai combiné le meilleur de divers articles, je suis venu avec ceci, en utilisant Javascript moderne:
L'espoir peut être utile à n'importe qui
la source
Cette version n'est pas idéale à toutes fins, et tout le monde n'aime pas les expressions virgule, mais voici une ligne unique qui est une expression pure, créant une nouvelle copie:
Une version légèrement améliorée des performances renvoie le tableau d'entrée si aucun déplacement n'est nécessaire, c'est toujours OK pour une utilisation immuable, car le tableau ne changera pas, et c'est toujours une expression pure:
L'invocation de l'un ou l'autre est
c'est-à-dire qu'il repose sur la diffusion pour générer une nouvelle copie. L'utilisation d'une arité fixe 3
move
mettrait en péril la propriété d'expression unique, ou la nature non destructive, ou l'avantage de performance desplice
. Encore une fois, il s'agit davantage d'un exemple qui répond à certains critères que d'une suggestion d'utilisation en production.la source
Array.move.js
Sommaire
Déplace les éléments dans un tableau, renvoyant un tableau contenant les éléments déplacés.
Syntaxe
Paramètres
index : Index auquel déplacer les éléments. S'il est négatif, l' indice commencera à la fin.
howMany : nombre d'éléments à déplacer de l' index .
toIndex : Index du tableau sur lequel placer les éléments déplacés. S'il est négatif, toIndex commencera à la fin.
Usage
Polyfill
la source
.move
semble fonctionner (je ne l'ai pas testé), vous devez noter qu'il ne fait partie d'aucune norme. Il est également bon d'avertir les gens que les fonctions polyfill / monkeypatched peuvent casser du code qui suppose que tout ce qui est énumérable est le leur.J'ai utilisé la belle réponse de @Reid , mais j'ai eu du mal à déplacer un élément de la fin d'un tableau un peu plus loin - au début (comme dans une boucle ). Par exemple ['a', 'b', 'c'] devrait devenir ['c', 'a', 'b'] en appelant .move (2,3)
J'ai réalisé cela en changeant le cas pour new_index> = this.length.
la source
En complément de l'excellente réponse de Reid (et parce que je ne peux pas faire de commentaire); Vous pouvez utiliser modulo pour faire "survoler" des indices négatifs et des indices trop grands:
la source
la source
Je pensais que c'était un problème de swap mais ce n'est pas le cas. Voici ma solution monoplace:
Voici un petit test:
la source
résultat:
la source
la source
la source
Version immuable sans copie de tableau:
la source
Je pense que la meilleure façon est de définir une nouvelle propriété pour les tableaux
la source
Une autre variante JS pure utilisant l'opérateur de propagation de tableau ES6 sans mutation
la source
Cette méthode préservera le tableau d'origine et vérifiera les erreurs de délimitation.
la source