Elementos de matriz de intercambio de Javascript

228

¿Hay alguna forma más simple de intercambiar dos elementos en una matriz?

var a = list[x], b = list[y];
list[y] = a;
list[x] = b;
conocido
fuente

Respuestas:

412

Solo necesita una variable temporal.

var b = list[y];
list[y] = list[x];
list[x] = b;

Edite la respuesta principal de secuestro 10 años después con mucha adopción de ES6 bajo nuestros cinturones:

Dada la matriz arr = [1,2,3,4], puede intercambiar valores en una línea ahora así:

[arr[0], arr[1]] = [arr[1], arr[0]];

Esto produciría la matriz [2,1,3,4]. Esta es una tarea desestructuradora .

tvanfosson
fuente
2
Incluso sin utilizar ECMAScript 6 Destructuring Assignment, en realidad puede lograr un intercambio simultáneo sin contaminar el alcance actual con una variable temporal: a = [b, b = a][0];como lo señaló @Jan, aunque todavía me encuentro utilizando el enfoque de variable temporal como lenguaje cruzado (por ejemplo, C / C ++ ) y el primer enfoque que suele aparecer en mi mente.
Ultimater
3
Puede intercambiar en su lugar (mutar) con es6 como se muestra a continuación:[ list[y], list[x] ] = [ list[x], list[y] ];
protoEvangelion
[arr[0], arr[1]] = [arr[1], arr[0]]producir solo [2, 1]sin el resto de la matriz
Yerko Palma
8
@YerkoPalma: la expresión devuelve [2,1], pero la matriz original se mutará a [2,1,3,4]
danbars el
111

Si desea una sola expresión, utilizando JavaScript nativo, recuerde que el valor de retorno de una operación de empalme contiene los elementos que se eliminaron.

var A = [1, 2, 3, 4, 5, 6, 7, 8, 9], x= 0, y= 1;
A[x] = A.splice(y, 1, A[x])[0];
alert(A); // alerts "2,1,3,4,5,6,7,8,9"

Editar:

El [0]es necesario al final de la expresión, ya que Array.splice()devuelve una matriz, y en esta situación requerimos el único elemento en la matriz devuelta.

Kennebec
fuente
3
empalme devuelve una matriz. Entonces, en su ejemplo, después de la operación de intercambio, su matriz realmente se ve así: [[2], 1, 3, 4, 5, 6, 7, 8, 9]
JPot
1
A [x] = A.plice (y, 1, A [x]) [0]; ? en mootools Array.implement ({swap: function (x, y) {this [y] = this.splice (x, 1, this [y]) [0];}});
Ken
Confirmado, falta el [0].
Johann Philipp Strathausen
agradable y breve, pero como dijo @aelgoa, casi lento y simple intercambio
ofir_aghai
75

Esto parece estar bien ...

var b = list[y];
list[y] = list[x];
list[x] = b;

Howerver usando

var b = list[y];

significa que una variable b va a estar presente para el resto del alcance. Esto puede conducir a una pérdida de memoria. Improbable, pero aún mejor evitarlo.

Quizás sea una buena idea poner esto en Array.prototype.swap

Array.prototype.swap = function (x,y) {
  var b = this[x];
  this[x] = this[y];
  this[y] = b;
  return this;
}

que se puede llamar como:

list.swap( x, y )

Este es un enfoque limpio para evitar pérdidas de memoria y SECO .

Stefan
fuente
Me gusta esto también. Array.implement ({swap: function (x, y) {x = this [x]; this [x] = this [y]; this [y] = x; return this;}});
ken
1
Esto es bonito. Tal vez algunos límites de verificación? Array.prototype.swap = function (x,y) { if (x >= 0 && x < this.length && y >= 0 && y < this.length) { var b = this[x]; this[x] = this[y]; this[y] = b; } return this; };
David R.
@DavidR. La verificación de límites es superflua e innecesaria. La persona que llama tiene todo lo necesario para realizar dicha verificación si lo desea, aunque en la mayoría de los casos ya sabe que x e y están dentro de los límites porque está en algún tipo de bucle.
Neil
66
¿No podría evitar la "pérdida potencial de memoria" simplemente envolviéndola en una función?
Carcigenicate
3
Para evitar el posible contratiempo de "aplanamiento", no tocaría la cadena de prototipos de ningún tipo incorporado.
AaronDancer
55

Según una persona aleatoria en Metafilter , "las versiones recientes de Javascript le permiten hacer intercambios (entre otras cosas) mucho más claramente:"

[ list[x], list[y] ] = [ list[y], list[x] ];

Mis pruebas rápidas mostraron que este código Pythonic funciona muy bien en la versión de JavaScript utilizada actualmente en "Google Apps Script" (".gs"). Por desgracia, otras pruebas muestran que este código proporciona un "Error de referencia no capturado: lado izquierdo no válido en la asignación". en cualquier versión de JavaScript (".js") utilizada por Google Chrome Versión 24.0.1312.57 m.

David Cary
fuente
2
Esto es parte de la propuesta de ES6: aún no está formalizado, por lo que no se debe asumir absolutamente que funcione en todas partes (sería increíble si lo hiciera ...).
Isiah Meadows
2
Funciona en la última versión actual de Firefox (39.0.3).
Jamie
2
Funciona en Chrome versión 54.0.2840.71 y versiones anteriores. Además, este debería ser su código de acceso si usa un transpilador ES6 como babel .
amee
3
Amo esta solución. Limpio, según lo previsto. Lástima que la pregunta se hizo hace 9 años ...
DavidsKanal
2
se ha estandarizado en es6 y esta característica se llama desestructuración.
AL-zami
29

Bueno, no necesita almacenar ambos valores, solo uno:

var tmp = list[x];
list[x] = list[y];
list[y] = tmp;
Marc Gravell
fuente
13
su 'tmp' suena más razonable de usar que 'b'
mtasic85
@ofir_aghai sí, tienes razón: hace más de 10 años, se publicó otra respuesta 22 segundos antes de esta (12: 14: 16Z vs 12: 14: 38Z) ...
Marc Gravell
en el día normal, me quedé con eso. pero solo porque la cuestión de segundos y el respeto de tus 10 años se reanudan aquí ;-)
ofir_aghai
lo siento, no me deja cambiar el voto .. "Su voto ahora está bloqueado a menos que se
edite
22

Puede intercambiar elementos en una matriz de la siguiente manera:

list[x] = [list[y],list[y]=list[x]][0]

Vea el siguiente ejemplo:

list = [1,2,3,4,5]
list[1] = [list[3],list[3]=list[1]][0]
//list is now [1,4,3,2,5]

Nota: funciona de la misma manera para variables regulares

var a=1,b=5;
a = [b,b=a][0]
ene
fuente
66
Esto es muy similar a la forma correcta estándar de hacer esto en ES6 (próxima versión de JavaScript): [list[x], list[y]] = [list[y], list[x]];.
Isiah Meadows
1
Esto no tiene nada que ver con el intercambio de matrices ES6 por desestructuración. Este es solo un uso inteligente del flujo de trabajo de JS. Un hermoso patrón de intercambio si usa codificación en línea con frecuencia, comothis[0] > this[1] && (this[0] = [this[1],this[1]=this[0]][0]);
Redu
18

Con valores numéricos puede evitar una variable temporal utilizando bitor xor

list[x] = list[x] ^ list[y];
list[y] = list[y] ^ list[x];
list[x] = list[x] ^ list[y];

o una suma aritmética (teniendo en cuenta que esto solo funciona si x + y es menor que el valor máximo para el tipo de datos)

list[x] = list[x] + list[y];
list[y] = list[x] - list[y];
list[x] = list[x] - list[y];
Jakub Arnold
fuente
2
¿Es ese Darth como en Vader? +1
krosenvold
77
Algo está mal. ¿No list[y] = list[x] - list[x];solo equivale a list[y] = 0;?
ErikE
3
El truco xor también falla cuando x = y: establece la lista [x] en cero, cuando puede esperar que mantenga la lista [x] como el valor original.
David Cary
1
Técnicamente, crea un valor temporal, simplemente no lo mueve fuera del área relevante de la matriz.
Mark Smit
1
Ni más simple, ni más eficiente, ni genérico.
LoganMzz
17

Esto no existía cuando se hizo la pregunta, pero ES2015 introdujo la desestructuración de la matriz, lo que le permite escribirla de la siguiente manera:

let a = 1, b = 2;
// a: 1, b: 2
[a, b] = [b, a];
// a: 2, b: 1
dirkdig
fuente
14
Para intercambiar así dentro de la matriz:[list[x], list[y]] = [list[y], list[x]];
Stromata
15

Para intercambiar dos elementos consecutivos de la matriz

array.splice(IndexToSwap,2,array[IndexToSwap+1],array[IndexToSwap]);
Piyush Madan
fuente
13

Recopilación de http://www.greywyvern.com/?post=265

var a = 5, b = 9;    
b = (a += b -= a) - b;    
alert([a, b]); // alerts "9, 5"
R-way Orz
fuente
1
Si envuelve esto en una swap(a, b)función, no necesita preocuparse por la legibilidad.
AccidentalTaylorExpansion
1
Funciona solo para enteros
Reduce
Esto probablemente se optimiza mal. Un compilador puede detectarlo como un "modismo de intercambio", pero no puede estar seguro de los efectos a menos que pueda estar seguro de que ambos tipos son ints y también de que no tienen alias .
mwfearnley
10

¿Qué pasa con Destructuring_assignment

var arr = [1, 2, 3, 4]
[arr[index1], arr[index2]] = [arr[index2], arr[index1]]

que también se puede extender a

[src order elements] => [dest order elements]
ROROROOROROR
fuente
9

Considere tal solución sin necesidad de definir la tercera variable:

function swap(arr, from, to) {
  arr.splice(from, 1, arr.splice(to, 1, arr[from])[0]);
}

var letters = ["a", "b", "c", "d", "e", "f"];

swap(letters, 1, 4);

console.log(letters); // ["a", "e", "c", "d", "b", "f"]

Nota: es posible que desee agregar comprobaciones adicionales, por ejemplo, para la longitud de la matriz. Esta solución es mutable, por lo que la swapfunción no necesita devolver una nueva matriz, solo hace la mutación sobre la matriz pasada.

Shevchenko Viktor
fuente
Además, el operador de propagación también podría usarse:arr.splice(from, 1, arr.splice(to, 1, ...arr[from]))
Orkun Tuzel el
7

Puede intercambiar cualquier cantidad de objetos o literales, incluso de diferentes tipos, utilizando una función de identidad simple como esta:

var swap = function (x){return x};
b = swap(a, a=b);
c = swap(a, a=b, b=c);

Para su problema:

var swap = function (x){return x};
list[y]  = swap(list[x], list[x]=list[y]);

Esto funciona en JavaScript porque acepta argumentos adicionales incluso si no se declaran ni se utilizan. Las asignaciones a=b, etc., suceden después de apasar a la función.

dansalmo
fuente
Hacker ... pero que podría ser una mejor, si sólo se está utilizando la función de una vez: list[y] = (function(x){return x})(list[x],list[x]=list[y]);. O, si usted está interesado en la ES6 (próxima versión de JS), que es increíblemente fácil: [list[x], list[y]] = [list[y], list[x]. Estoy muy contento de que estén agregando algunos aspectos más funcionales y basados ​​en clases en la próxima versión de JavaScript.
Isiah Meadows
6

Para dos o más elementos (número fijo)

[list[y], list[x]] = [list[x], list[y]];

¡No se requiere una variable temporal!

Estaba pensando en simplemente llamar list.reverse().
Pero luego me di cuenta de que funcionaría como intercambio solo cuando list.length = x + y + 1.

Para un número variable de elementos

He examinado varias construcciones Javascript modernas para este efecto, incluyendo Map y map , pero lamentablemente ninguna ha resultado en un código que sea más compacto o más rápido que esta construcción antigua basada en bucles:

function multiswap(arr,i0,i1) {/* argument immutable if string */
    if (arr.split) return multiswap(arr.split(""), i0, i1).join("");
    var diff = [];
    for (let i in i0) diff[i0[i]] = arr[i1[i]];
    return Object.assign(arr,diff);
}

Example:
    var alphabet = "abcdefghijklmnopqrstuvwxyz";
    var [x,y,z] = [14,6,15];
    var output = document.getElementsByTagName("code");
    output[0].innerHTML = alphabet;
    output[1].innerHTML = multiswap(alphabet, [0,25], [25,0]);
    output[2].innerHTML = multiswap(alphabet, [0,25,z,1,y,x], [25,0,x,y,z,3]);
<table>
    <tr><td>Input:</td>                        <td><code></code></td></tr>
    <tr><td>Swap two elements:</td>            <td><code></code></td></tr>
    <tr><td>Swap multiple elements:&nbsp;</td> <td><code></code></td></tr>
</table>

7vujy0f0hy
fuente
5

Hay una forma interesante de intercambio:

var a = 1;
var b = 2;
[a,b] = [b,a];

(Forma ES6)

Vivek
fuente
55
para una matriz, que es másvar a= [7,8,9,10], i=2, j=3;[a[i],a[j]] = [a[j],a[i]];
CAUB
4
var a = [1,2,3,4,5], b=a.length;

for (var i=0; i<b; i++) {
    a.unshift(a.splice(1+i,1).shift());
}
a.shift();
//a = [5,4,3,2,1];
Nathan Romano
fuente
3

Aquí hay una frase que no muta list:

let newList = Object.assign([], list, {[x]: list[y], [y]: list[x]})

(Utiliza funciones de idioma que no estaban disponibles en 2009 cuando se publicó la pregunta)

fmg
fuente
1

Aquí hay un valor de intercambio de versión compacta en i1 con i2 en arr

arr.slice(0,i1).concat(arr[i2],arr.slice(i1+1,i2),arr[i1],arr.slice(i2+1))
usuario2044802
fuente
Eso es menos eficiente que el método de variable temporal. Efectivamente, está devolviendo una matriz modificada que se cortó tres veces y se concatenó junto con dos objetos entre las tres matrices divididas. Efectivamente, ha requerido más del doble de memoria de la necesaria para obtener el valor que simplemente se asigna a la matriz (nada de eso se hizo en su lugar).
Isiah Meadows
1

Aquí hay una variación que primero verifica si el índice existe en la matriz:

Array.prototype.swapItems = function(a, b){
    if(  !(a in this) || !(b in this) )
        return this;
    this[a] = this.splice(b, 1, this[a])[0];
    return this;
}

Actualmente solo regresará thissi el índice no existe, pero podría modificar fácilmente el comportamiento en caso de falla

Douglas.Sesar
fuente
1

Intercambie el primer y el último elemento en una matriz sin variable temporal o método de intercambio ES6 [a, b] = [b, a]

[a.pop(), ...a.slice(1), a.shift()]

gengns
fuente
1

Solución mecanografiada que clona la matriz en lugar de mutar la existente

export function swapItemsInArray<T>(items: T[], indexA: number, indexB: number): T[] {
  const itemA = items[indexA];

  const clone = [...items];

  clone[indexA] = clone[indexB];
  clone[indexB] = itemA;

  return clone;
}
pie6k
fuente
0

Solo por el gusto de hacerlo, otra forma sin usar ninguna variable adicional sería:

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

// swap index 0 and 2
arr[arr.length] = arr[0];   // copy idx1 to the end of the array
arr[0] = arr[2];            // copy idx2 to idx1
arr[2] = arr[arr.length-1]; // copy idx1 to idx2
arr.length--;               // remove idx1 (was added to the end of the array)


console.log( arr ); // -> [3, 2, 1, 4, 5, 6, 7, 8, 9]

vsync
fuente
0

En aras de la brevedad, aquí está la versión fea de una sola línea que es solo un poco menos fea que toda esa concat y rebanadas anteriores. La respuesta aceptada es realmente el camino a seguir y mucho más legible.

Dado:

var foo = [ 0, 1, 2, 3, 4, 5, 6 ];

si desea intercambiar los valores de dos índices (a y b); entonces esto lo haría:

foo.splice( a, 1, foo.splice(b,1,foo[a])[0] );

Por ejemplo, si desea intercambiar el 3 y el 5, puede hacerlo de esta manera:

foo.splice( 3, 1, foo.splice(5,1,foo[3])[0] );

o

foo.splice( 5, 1, foo.splice(3,1,foo[5])[0] );

Ambos producen el mismo resultado:

console.log( foo );
// => [ 0, 1, 2, 5, 4, 3, 6 ]

#splicehatersarepunks :)

Jasonovich
fuente
0

Si no desea utilizar la variable temporal en ES5, esta es una forma de intercambiar elementos de la matriz.

var swapArrayElements = function (a, x, y) {
  if (a.length === 1) return a;
  a.splice(y, 1, a.splice(x, 1, a[y])[0]);
  return a;
};

swapArrayElements([1, 2, 3, 4, 5], 1, 3); //=> [ 1, 4, 3, 2, 5 ]
venkat7668
fuente
De esta manera, en lugar de crear una variable temporal, está creando 2 nuevas matrices, ya que a.splicedevuelve una matriz con los elementos eliminados. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
XCS
¿Hay alguna manera de que podamos hacerlo mejor? @Cristy
venkat7668
La respuesta aceptada es directa. Esto será útil cuando tenga una limitación en la declaración de número de variables (principalmente propósito de la entrevista :)). Pero no es eficiente en memoria como mencionaste. @Cristy
venkat7668
Personalmente, creo que es una mala práctica y no debería recomendarse a los principiantes. También es muy difícil de leer.
XCS
0

prueba esta función ...

$(document).ready(function () {
        var pair = [];
        var destinationarray = ['AAA','BBB','CCC'];

        var cityItems = getCityList(destinationarray);
        for (var i = 0; i < cityItems.length; i++) {
            pair = [];
            var ending_point = "";
            for (var j = 0; j < cityItems[i].length; j++) {
                pair.push(cityItems[i][j]);
            }
            alert(pair);
            console.log(pair)
        }

    });
    function getCityList(inputArray) {
        var Util = function () {
        };

        Util.getPermuts = function (array, start, output) {
            if (start >= array.length) {
                var arr = array.slice(0);
                output.push(arr);
            } else {
                var i;

                for (i = start; i < array.length; ++i) {
                    Util.swap(array, start, i);
                    Util.getPermuts(array, start + 1, output);
                    Util.swap(array, start, i);
                }
            }
        }

        Util.getAllPossiblePermuts = function (array, output) {
            Util.getPermuts(array, 0, output);
        }

        Util.swap = function (array, from, to) {
            var tmp = array[from];
            array[from] = array[to];
            array[to] = tmp;
        }
        var output = [];
        Util.getAllPossiblePermuts(inputArray, output);
        return output;
    }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

bilal chaudhari
fuente
0

var arr = [1, 2];
arr.splice(0, 2, arr[1], arr[0]);
console.log(arr); //[2, 1]

JATIN KUMAR NAYAK
fuente
1
Si bien este fragmento de código puede resolver la pregunta, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo la pregunta para los lectores en el futuro, y que esas personas podrían no conocer los motivos de su sugerencia de código.
Alessio
-1

Usando ES6 es posible hacerlo así ...

Imagina que tienes estas 2 matrices ...

const a = ["a", "b", "c", "d", "e"];
const b = [5, 4, 3, 2, 1];

y quieres intercambiar los primeros valores:

const [a0] = a;
a[0] = b[0];
b[0] = a0;

y valor:

a; //[5, "b", "c", "d", "e"]
b; //["a", 4, 3, 2, 1]
Alireza
fuente
-2
Array.prototype.swap = function(a, b) {
  var temp = this[a];
  this[a] = this[b];
  this[b] = temp;
};

Uso:

var myArray = [0,1,2,3,4...];
myArray.swap(4,1);
usuario2472643
fuente
1
No hay necesidad de ser grosero. Además, extender el Arrayprototipo no era parte de lo que se solicitó, puede confundir más de lo que hace bien.
Mathias Lykkegaard Lorenzen
¿Cómo está expresando que algunas de las respuestas están locos y extender el prototipo de array sería y añadiendo un retorno que esto haría encadenan poder ...
user2472643
2
Lo estás expresando como "la forma correcta". Puede dar la impresión equivocada. En cambio, sugeriría mencionar lo que está haciendo (extender el prototipo) y cómo es útil, exactamente como me acaba de describir.
Mathias Lykkegaard Lorenzen
1
gotcha, lo siento, mi aplomo no está en pareja a veces ^ _ ^
user2472643
2
Usted es el único que describe un problema con el contexto de la respuesta ... en primer lugar, las puntuaciones negativas deben reservarse para las respuestas que no funcionan. En segundo lugar, esta es una buena respuesta con un uso elegante que no causa conflictos. Juzgue el código, no la entrega. También en mi respuesta, si lo eliminó y excluyó la extensión del prototipo, se convierte exactamente en la respuesta más votada, por lo que el hecho de que sea -6 muestra la falta de pensamiento de las personas que lo rechazaron. Y fue publicado meses antes de la respuesta principal ... así que esto suena como una popularidad, no un concurso de códigos.
user2472643
-3

Si es necesario, intercambie solo el primer y el último elemento:

array.unshift( array.pop() );
Alex Moonlight
fuente
Este código es defectuoso. Toma el último elemento de la matriz y luego lo coloca al principio, eso no es intercambio. Este código hace esto: en [1, 2, 3] => [3, 1, 2]lugar de [1, 2, 3] => [3, 2, 1].
David Archibald