Элементы массива подкачки 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]. Это деструктурирующее задание .

tvanfosson
источник
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()возвращает массив, и в этой ситуации , мы требуем , чтобы один элемент в возвращаемом массиве.

Kennebec
источник
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
dirkdig
источник
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"
R-way Orz
источник
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]
ROROROOROROR
источник
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передачи в функцию.

dansalmo
источник
Хак ... но вы могли бы сделать один лучше, если вы только с помощью функции один раз: 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>

7vujy0f0hy
источник
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]];
совещание
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];
Натан Романо
источник
3

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

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

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

FMG
источник
1

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

arr.slice(0,i1).concat(arr[i2],arr.slice(i1+1,i2),arr[i1],arr.slice(i2+1))
user2044802
источник
Это менее эффективно, чем метод временных переменных. Вы фактически возвращаете модифицированный массив, который был разрезан три раза и соединен вместе с двумя объектами между тремя нарезанными массивами. Вы фактически потребовали более чем в два раза больше памяти, чем необходимо, чтобы получить значение для простого присвоения массиву (ничего из этого не было сделано на месте).
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если индекс не существует, но вы можете легко изменить поведение при сбое

Douglas.Sesar
источник
1

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

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

gengns
источник
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;
}
pie6k
источник
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]

VSync
источник
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 :)

Jasonovich
источник
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 ]
venkat7668
источник
Таким образом, вместо создания временной переменной вы создаете 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);
user2472643
источник
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].
Дэвид Арчибальд