Элементы массива подкачки Javascript


228

Есть ли более простой способ поменять два элемента в массиве?

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

Ответы:


412

Вам нужна только одна временная переменная.

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

Отредактируйте верхний ответ 10 лет спустя, получив множество ES6 под нашими поясами:

Учитывая массив arr = [1,2,3,4], вы можете поменять значения в одну строку, вот так:

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

Это произведет массив [2,1,3,4]. Это деструктурирующее задание .


2
Даже без использования ECMAScript 6 Destructuring Assignment, на самом деле можно добиться одновременного обмена без загрязнения текущей области с помощью временной переменной: a = [b, b = a][0];как указал @Jan Хотя я все еще использую метод временных переменных, так как он кросс-языковой (например, C / C ++) ) и первый подход, который обычно приходит мне в голову.
Ultimater

3
Вы можете поменять местами (мутировать) с es6, как показано ниже:[ list[y], list[x] ] = [ list[x], list[y] ];
protoEvangelion

[arr[0], arr[1]] = [arr[1], arr[0]]производить только [2, 1]без остальной части массива
Ерко Пальма

8
@YerkoPalma - выражение возвращает [2,1], но исходный массив будет преобразован в [2,1,3,4]
danbars

111

Если вам нужно одно выражение с использованием собственного javascript, помните, что возвращаемое значение из операции сращивания содержит элементы, которые были удалены.

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"

Редактировать:

[0]Необходимо в конце выражения , как Array.splice()возвращает массив, и в этой ситуации , мы требуем , чтобы один элемент в возвращаемом массиве.


3
splice возвращает массив. Итак, в вашем примере после операции подкачки ваш массив выглядит так: [[2], 1, 3, 4, 5, 6, 7, 8, 9]
JPot

1
A [x] = A.splice (y, 1, A [x]) [0]; ? в mootools Array.implement ({swap: function (x, y) {this [y] = this.splice (x, 1, this [y]) [0];}});
Кен

Подтверждено, что [0] отсутствует.
Иоганн Филипп Стратхаузен

хороший и короткий, но, как сказал @aelgoa, почти медленный, а затем простой обмен
ofir_aghai

75

Это кажется хорошо ....

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

Hoverver с помощью

var b = list[y];

означает, что переменная b будет присутствовать для остальной части области. Это может привести к утечке памяти. Вряд ли, но все же лучше избегать.

Может быть, хорошая идея поместить это в Array.prototype.swap

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

который можно назвать как:

list.swap( x, y )

Это чистый подход, позволяющий избежать утечек памяти и СУХОГО .


Мне это тоже нравится. Array.implement ({swap: function (x, y) {x = this [x]; this [x] = this [y]; this [y] = x; вернуть this;}});
Кен

1
Это хорошо. Может быть, некоторые проверки границ? 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; };
Дэвид Р.

@DavidR. Проверка границ является излишней и ненужной. Вызывающая сторона имеет все необходимое для выполнения такой проверки, если это необходимо, хотя в большинстве случаев вы уже знаете, что x и y находятся в границах, потому что вы находитесь в каком-то цикле.
Нил

6
Не могли бы вы избежать «потенциальной утечки памяти», просто обернув ее в функцию?
Carcigenicate

3
Чтобы избежать потенциального «сглаживания» неудач, я бы не стал касаться цепочки прототипов любых встроенных типов.
AaronDancer

55

По словам случайного человека из Metafilter , «последние версии Javascript позволяют вам делать свопы (между прочим) гораздо более аккуратно:»

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

Мои быстрые тесты показали, что этот код Pythonic отлично работает в версии JavaScript, используемой в настоящее время в «Google Apps Script» («.gs»). Увы, дальнейшие тесты показывают, что этот код выдает «Uncaught ReferenceError: Недопустимая левая часть в назначении». в любой версии JavaScript (".js") используется Google Chrome версии 24.0.1312.57 m.


2
Это часть предложения ES6: оно еще не формализовано, поэтому не следует считать, что оно будет работать везде (было бы замечательно, если бы оно работало ...).
Isiah Meadows

2
Он работает в текущей версии Firefox (39.0.3).
Джейми

2
Он работает в Chrome версии 54.0.2840.71 и более ранних версиях. Кроме того, это должен быть ваш код, если вы используете ES6-транспортер, такой как babel .
Amoebe

3
Люблю это решение. Чисто, как задумано. Жаль, что вопрос был задан 9 лет назад ...
DavidsKanal

2
он был стандартизирован в es6, и эта функция называется деструктуризацией.
AL-zami

29

Ну, вам не нужно буферизовать оба значения - только одно:

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

13
ваш «tmp» звучит более разумно, чем «b»
mtasic85

@ofir_aghai да, вы правы: 10+ лет назад был опубликован еще один ответ за 22 секунды до этого (12: 14: 16Z против 12: 14: 38Z) ...
Марк Гравелл

в обычный день я придерживался этого. но только потому, что секундная проблема и уважение ваших 10 лет возобновляются здесь ;-)
ofir_aghai

извините, это не позволяет мне изменить голос. "Ваш голос теперь заблокирован, если этот ответ не отредактирован"
ofir_aghai

22

Вы можете поменять местами элементы в массиве следующим образом:

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

Смотрите следующий пример:

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

Примечание: это работает так же для обычных переменных

var a=1,b=5;
a = [b,b=a][0]

6
Это поразительно похож на стандартный правильный способ сделать это в ES6 (следующая версия JavaScript) [list[x], list[y]] = [list[y], list[x]];.
Isiah Meadows

1
Это не имеет ничего общего с обменом массивов ES6 путем деструктуризации. Это просто умное использование рабочего процесса JS. Красивый шаблон замены , если вы используете встроенное кодирование часто, напримерthis[0] > this[1] && (this[0] = [this[1],this[1]=this[0]][0]);
Ред

18

С числовыми значениями вы можете избежать временной переменной, используя побитовый xor

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

или арифметическая сумма (учитывая, что это работает, только если x + y меньше максимального значения для типа данных)

list[x] = list[x] + list[y];
list[y] = list[x] - list[y];
list[x] = list[x] - list[y];

2
Это дартс, как в Вейдере? +1
кросенволд

7
Что-то не так. Не list[y] = list[x] - list[x];просто приравнивать к list[y] = 0;?
ErikE

3
Трюк xor также не срабатывает, когда x = y - он устанавливает list [x] в ноль, когда можно ожидать, что list [x] сохранит исходное значение.
Дэвид Кэри

1
Технически вы делаете временное значение, вы просто не перемещаете его за пределы соответствующей области массива.
Марк Смит

1
Ни проще, ни эффективнее, ни универсальнее.
LoganMzz

17

Этого не было, когда задавался вопрос, но ES2015 ввел деструктуризацию массива, что позволило написать его следующим образом:

let a = 1, b = 2;
// a: 1, b: 2
[a, b] = [b, a];
// a: 2, b: 1

14
Чтобы поменять местами этот массив:[list[x], list[y]] = [list[y], list[x]];
Стромата

15

Поменять местами два последовательных элемента массива

array.splice(IndexToSwap,2,array[IndexToSwap+1],array[IndexToSwap]);

13

Дайджест от http://www.greywyvern.com/?post=265

var a = 5, b = 9;    
b = (a += b -= a) - b;    
alert([a, b]); // alerts "9, 5"

1
Если вы заключите это в swap(a, b)функцию, вам не нужно беспокоиться о читабельности.
AccidentalTaylorExpansion

1
Работает только для целых чисел
Ред.

Это, вероятно, плохо оптимизирует. Компилятор может определить его как «идиома подкачки», но не может быть уверен в его эффектах, если не уверен, что оба типа являются целочисленными, а также что они не являются псевдонимами .
mwfearnley

10

как насчет Destructuring_assignment

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

который также может быть расширен до

[src order elements] => [dest order elements]

9

Рассмотрим такое решение без необходимости определять третью переменную:

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"]

Примечание: вы можете добавить дополнительные проверки, например, для длины массива. Это решение является изменяемым, поэтому swapфункция не должна возвращать новый массив, она просто выполняет мутацию переданного массива.


Кроме того, оператор спреда также может быть использован:arr.splice(from, 1, arr.splice(to, 1, ...arr[from]))
Orkun Tuzel

7

Вы можете поменять местами любое количество объектов или литералов, даже разных типов, используя простую функцию идентификации, например:

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

Для вашей проблемы:

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

Это работает в JavaScript, потому что он принимает дополнительные аргументы, даже если они не объявлены или не используются. Назначения и a=bт. Д. Происходят после aпередачи в функцию.


Хак ... но вы могли бы сделать один лучше, если вы только с помощью функции один раз: list[y] = (function(x){return x})(list[x],list[x]=list[y]);. Или, если вы заинтересованы в ES6 (следующая версия JS), это безумно легко: [list[x], list[y]] = [list[y], list[x]. Я так рад, что они добавили еще несколько функциональных и основанных на классах аспектов в следующую версию JavaScript.
Isiah Meadows

6

Для двух или более элементов (фиксированное число)

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

Временная переменная не требуется!

Я думал просто позвонить list.reverse().
Но потом я понял, что своп будет работать только тогда, когда list.length = x + y + 1.

Для переменного количества элементов

Я рассмотрел различные современные конструкции Javascript на этот счет, включая Map и map , но, к сожалению, ни одна из них не привела к созданию кода, который был бы более компактным или более быстрым, чем эта старомодная конструкция на основе циклов:

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>


5

Есть один интересный способ обмена:

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

(ES6 способ)


5
для массива, это большеvar a= [7,8,9,10], i=2, j=3;[a[i],a[j]] = [a[j],a[i]];
совещание


3

Вот одна строка, которая не мутирует list:

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

(Использует языковые функции, недоступные в 2009 году, когда вопрос был опубликован!)


1

Вот компактная версия меняет значение на i1 с i2 в обр

arr.slice(0,i1).concat(arr[i2],arr.slice(i1+1,i2),arr[i1],arr.slice(i2+1))

Это менее эффективно, чем метод временных переменных. Вы фактически возвращаете модифицированный массив, который был разрезан три раза и соединен вместе с двумя объектами между тремя нарезанными массивами. Вы фактически потребовали более чем в два раза больше памяти, чем необходимо, чтобы получить значение для простого присвоения массиву (ничего из этого не было сделано на месте).
Isiah Meadows

1

Вот вариант, который сначала проверяет, существует ли индекс в массиве:

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;
}

В настоящее время он просто вернется, thisесли индекс не существует, но вы можете легко изменить поведение при сбое


1

Поменяйте местами первый и последний элемент в массиве без временной переменной или метода обмена ES6 [a, b] = [b, a]

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


1

Решение Typescript, которое клонирует массив, а не изменяет существующий

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;
}

0

Просто для удовольствия, другой способ без использования какой-либо дополнительной переменной будет:

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]


0

Для краткости, вот уродливая версия с одной линией, которая только немного менее уродлива, чем вся эта конкатата и нарезка выше. Принятый ответ - действительно путь, и более читаемый.

Дано:

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

если вы хотите поменять местами значения двух индексов (a и b); тогда это будет сделано:

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

Например, если вы хотите поменять местами 3 и 5, вы можете сделать это следующим образом:

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

или

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

Оба дают одинаковый результат:

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

#splicehatersarepunks :)


0

Если вы не хотите использовать временную переменную в ES5, это один из способов замены элементов массива.

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 ]

Таким образом, вместо создания временной переменной вы создаете 2 новых массива, которые a.spliceвозвращают массив с удаленными элементами. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
XCS

Есть ли способ, которым мы можем сделать это лучше? @Cristy
venkat7668

Принятый ответ является прямым. Это будет удобно, когда у вас есть ограничение на количество объявленных переменных (в основном для целей интервью :)). Но не эффективная память, как вы упомянули. @Cristy
venkat7668

Я лично считаю, что это плохая практика, и ее не следует рекомендовать новичкам. Это также очень трудно читать.
XCS

0

попробуйте эту функцию ...

$(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>


0

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


1
Хотя этот фрагмент кода может решить вопрос, в том числе объяснение действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин, по которым вы предлагаете код.
Алессио

-1

С помощью ES6 это можно сделать так ...

Представьте, что у вас есть эти 2 массива ...

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

и вы хотите поменять местами первые значения:

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

и значение:

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

-2
Array.prototype.swap = function(a, b) {
  var temp = this[a];
  this[a] = this[b];
  this[b] = temp;
};

Использование:

var myArray = [0,1,2,3,4...];
myArray.swap(4,1);

1
Не надо быть грубым. Кроме того, расширение Arrayпрототипа не было частью того, о чем просили - это может сбить с толку больше, чем принесет пользу.
Матиас Ликкегор Лоренцен

Как можно выразить, что некоторые из ответов являются сумасшедшими, расширить прототип массива и добавить возвращаемое значение, которое сделало бы его цепным ...
user2472643

2
Вы выражаете это как «правильный путь». Это может создать неправильное впечатление. Вместо этого я бы предложил упомянуть, что вы делаете (расширяете прототип) и как это полезно, именно так, как вы только что описали мне.
Матиас Ликкегор Лоренцен

1
Гоча, извините, моя уравновешенность иногда не в паре ^ _ ^
user2472643

2
Вы единственный, кто описывает проблему с контекстом ответа ... во-первых, отрицательные оценки должны быть зарезервированы для неработающих ответов. Во-вторых, это хороший ответ с элегантным использованием, которое не вызывает конфликтов. Судите код не доставки. Также в моем ответе, если вы урежете его и исключите расширение прототипа, оно станет точно таким же, как и ответ с наибольшим количеством голосов, так что тот факт, что это -6, показывает отсутствие мысли со стороны людей, которые проголосовали за него. И был опубликован за несколько месяцев до топ-ответа ... так что это звучит как популярность, а не соревнование кода.
user2472643

-3

Если нужно поменять местами только первый и последний элементы:

array.unshift( array.pop() );

Этот код неисправен. Он берет последний элемент массива, затем помещает его в начало, что не является заменой. Этот код делает это: [1, 2, 3] => [3, 1, 2]вместо [1, 2, 3] => [3, 2, 1].
Дэвид Арчибальд
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.