Как вставить элемент в массив по определенному индексу (JavaScript)?


2932

Я ищу метод вставки массива JavaScript, в стиле:

arr.insert(index, item)

Желательно в jQuery, но любая реализация JavaScript подойдет на этом этапе.


96
Обратите внимание, что JQuery - это библиотека DOM и управления событиями, а не собственный язык. Это не имеет ничего общего с манипулированием массивами.
Домино

25
api.jquery.com/jQuery.inArray не имеет ничего общего с DOM или событиями. jQuery превратился в смешанный инструментарий для разработки JS-браузеров, в результате чего люди ожидают, что у него будет метод для всего.
Тим

4
@Tim, но это все еще не свой собственный язык (все же есть некоторые вопросы, такие как «как сложить два числа в jQuery» здесь на SO)
Виктор

3
@Victor Нет, и никогда не будет. jQuery был полезен и актуален, но у него был свой день.
Тим

1
Кроме того, посмотрите на это , чтобы
изобразить

Ответы:


4758

То, что вы хотите, это spliceфункция над собственным объектом массива.

arr.splice(index, 0, item);вставит itemв arrуказанный индекс ( 0сначала удаляя элементы, то есть просто вставку).

В этом примере мы создадим массив и добавим в него элемент в индекс 2:

var arr = [];
arr[0] = "Jani";
arr[1] = "Hege";
arr[2] = "Stale";
arr[3] = "Kai Jim";
arr[4] = "Borge";

console.log(arr.join());
arr.splice(2, 0, "Lene");
console.log(arr.join());


168
Спасибо, я думал, что буду глупо спрашивать, но теперь, когда я знаю ответ, я не знаю! С какой стати они решили называть это сплайсингом, когда для той же функции обычно используется более удобный для поиска термин ?!
tags2k

83
@ tags2k: потому что функция делает больше, чем просто вставляет элементы, а ее имя уже установлено в perl?
Кристоф


55
Сращивание можно вставить, но так же часто нет . Например: arr.splice(2,3)удалит 3 элемента, начиная с индекса 2. Без передачи 3-го .... N-го параметра ничего не вставляется. Таким образом, имя insert()не делает это справедливо либо.
EBarr

14
Я думаю, что термин "сращивание" имеет смысл. Соединение означает присоединение или подключение, а также изменение. У вас есть установленный массив, который вы сейчас «меняете», что подразумевает добавление или удаление элементов. Вы указываете, где в массиве начинать, затем сколько старых элементов удалить (если они есть) и, наконец, необязательно, список новых элементов, которые нужно добавить. Конечно же, Splice - это отличный научный термин.
Якуб Келлер

285

Вы можете реализовать Array.insertметод, выполнив это:

Array.prototype.insert = function ( index, item ) {
    this.splice( index, 0, item );
};

Тогда вы можете использовать его как:

var arr = [ 'A', 'B', 'D', 'E' ];
arr.insert(2, 'C');

// => arr == [ 'A', 'B', 'C', 'D', 'E' ]

9
Чтобы вставить несколько предметов, вы можете использоватьArray.prototype.insert = function (index, items) { this.splice.apply(this, [index, 0].concat(items)); }
Райан Смит

7
Проблема с добавлением материала в массив состоит в том, что функция будет отображаться как элемент, когда вы делаете для (я в arr) {...}
rep_movsd

7
Но имейте в виду, что не рекомендуется расширять нативные типы, поскольку это может помешать другому коду или будущей функциональности.
Марс

17
Не изменяйте объекты, которыми вы не владеете
Луис Кабрера Бенито

4
Не модифицируйте прототипы
satya164

141

Помимо сращивания, вы можете использовать этот подход, который не будет изменять исходный массив, но создаст новый массив с добавленным элементом. Обычно вы должны избегать мутаций, когда это возможно. Я использую ES6 спред оператора здесь.

const items = [1, 2, 3, 4, 5]

const insert = (arr, index, newItem) => [
  // part of the array before the specified index
  ...arr.slice(0, index),
  // inserted item
  newItem,
  // part of the array after the specified index
  ...arr.slice(index)
]

const result = insert(items, 1, 10)

console.log(result)
// [1, 10, 2, 3, 4, 5]

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

const items = [1, 2, 3, 4, 5]

const insert = (arr, index, ...newItems) => [
  // part of the array before the specified index
  ...arr.slice(0, index),
  // inserted items
  ...newItems,
  // part of the array after the specified index
  ...arr.slice(index)
]

const result = insert(items, 1, 10, 20)

console.log(result)
// [1, 10, 20, 2, 3, 4, 5]


1
Это хороший, безопасный способ сделать это? Я спрашиваю, потому что это кажется таким элегантным и кратким, но никакие другие ответы не касаются этого. Большинство из них модифицируют прототип объекта!
Суровая Канчина

5
@HarshKanchina Это, вероятно , потому , что большинство ответов предварительно ES6, но этот подход является очень распространенным в настоящее время из моего опыта
GAFI

77

Пользовательские insertметоды массива

1. С несколькими аргументами и поддержкой цепочки

/* Syntax:
   array.insert(index, value1, value2, ..., valueN) */

Array.prototype.insert = function(index) {
    this.splice.apply(this, [index, 0].concat(
        Array.prototype.slice.call(arguments, 1)));
    return this;
};

Он может вставлять несколько элементов (как это spliceделает нативный ) и поддерживает цепочку:

["a", "b", "c", "d"].insert(2, "X", "Y", "Z").slice(1, 6);
// ["b", "X", "Y", "Z", "c"]

2. С поддержкой слияния и создания цепочек аргументов

/* Syntax:
   array.insert(index, value1, value2, ..., valueN) */

Array.prototype.insert = function(index) {
    index = Math.min(index, this.length);
    arguments.length > 1
        && this.splice.apply(this, [index, 0].concat([].pop.call(arguments)))
        && this.insert.apply(this, arguments);
    return this;
};

Он может объединять массивы из аргументов с данным массивом, а также поддерживает цепочку:

["a", "b", "c", "d"].insert(2, "V", ["W", "X", "Y"], "Z").join("-");
// "a-b-V-W-X-Y-Z-c-d"

ДЕМО: http://jsfiddle.net/UPphH/


Есть ли компактный способ слияния этой версии с массивом, когда он находит его в аргументах?
Nolo

Я не понимаю первый результат ["b", "X", "Y", "Z", "c"]. Почему не "d"входит? Мне кажется, что если вы установите 6 в качестве второго параметра slice()и в массиве есть 6 элементов, начиная с указанного индекса, то вы должны получить все 6 элементов в возвращаемом значении. (В документе говорится howManyоб этом параметре.) Developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Алексис Уилк

На самом деле, если я использую индекс 3 или более, я ничего не получаю в выводе (случай 1., FireFox) ["a", "b", "c", "d"].insert(2, "X", "Y", "Z").slice(3, 3);=>[ ]
Алексис Уилке

@AlexisWilke В первом примере я использовал sliceметод, а не метод splice, на который вы ссылаетесь в комментарии. Второй параметр slice(named end) - это индекс, начинающийся с нуля, на котором заканчивается извлечение. sliceвыдержки до, но не включаяend . Следовательно, после insertтого, как у вас есть ["a", "b", "X", "Y", "Z", "c", "d"], из которого sliceизвлекаются элементы с индексами от 1до 6, то есть от "b"до, "d"но не включая "d". Имеет ли это смысл?
VisioN 12.12.14

41

Если вы хотите вставить несколько элементов в массив одновременно, проверьте ответ Stack Overflow: лучший способ объединить массив в массив в javascript

Также вот несколько функций для иллюстрации обоих примеров:

function insertAt(array, index) {
    var arrayToInsert = Array.prototype.splice.apply(arguments, [2]);
    return insertArrayAt(array, index, arrayToInsert);
}

function insertArrayAt(array, index, arrayToInsert) {
    Array.prototype.splice.apply(array, [index, 0].concat(arrayToInsert));
    return array;
}

Наконец, вот jsFiddle, так что вы можете увидеть его сами: http://jsfiddle.net/luisperezphd/Wc8aS/

И вот как вы используете функции:

// if you want to insert specific values whether constants or variables:
insertAt(arr, 1, "x", "y", "z");

// OR if you have an array:
var arrToInsert = ["x", "y", "z"];
insertArrayAt(arr, 1, arrToInsert);

1
Разве не будет insertAt () лучше вызывать insertArrayAt () после создания одноэлементного arrayToInsert? Это позволяет избежать повторения идентичного кода.
Мэтт Сэч

1
это отличный пример того, когда использовать «применить»
CRice

Я добавил параметр removeCount в этот метод, чтобы воспользоваться преимуществами возможности сплайса также удалять элементы с этим индексом: Array.prototype.splice.apply (array, [index, removeCount || 0] .concat (arrayToInsert));
Крис

23

Для правильного функционального программирования и создания цепочек изобретение Array.prototype.insert()является существенным. На самом деле, сплайсинг мог бы быть идеальным, если бы он возвращал измененный массив вместо совершенно бессмысленного пустого массива. Так что здесь идет

Array.prototype.insert = function(i,...rest){
  this.splice(i,0,...rest)
  return this
}

var a = [3,4,8,9];
document.write("<pre>" + JSON.stringify(a.insert(2,5,6,7)) + "</pre>");

Хорошо, все вышеперечисленное с тем, что Array.prototype.splice()мутирует исходный массив, а некоторые могут жаловаться, что «вы не должны изменять то, что вам не принадлежит», и это может оказаться правильным. Поэтому для общественного блага я хотел бы дать другой, Array.prototype.insert()который не изменяет первоначальный массив. Здесь это идет;

Array.prototype.insert = function(i,...rest){
  return this.slice(0,i).concat(rest,this.slice(i));
}

var a = [3,4,8,9],
    b = a.insert(2,5,6,7);
console.log(JSON.stringify(a));
console.log(JSON.stringify(b));


2
«совершенно бессмысленный пустой массив» - он возвращает пустой массив только тогда, когда второй параметр равен 0. Если он больше 0, он возвращает элементы, удаленные из массива. Учитывая, что вы добавляете в прототип и spliceизменяете исходный массив, я не думаю, что «правильное функциональное программирование» принадлежит где-то поблизости splice.
chrisbajorin

Здесь речь идет о вставке, и второй параметр Array.prototype.splice () должен быть нулевым. И то, что он возвращает, не имеет никакого значения, кроме «я ничего не удалил», и поскольку мы используем его для вставки элемента, у нас уже есть эта информация. Если вы не хотите изменять исходный массив, вы можете сделать то же самое с двумя операциями Array.prototype.slice () и одной операцией Array.prototype.concat (). Тебе решать.
Редакция

1
Ваша вторая реализация является самой чистой из всей этой страницы, и у вас есть ноль голосов. Пожалуйста, возьми мой и продолжай в том же духе. (вы должны просто не мутировать прототип, но вы уже это знаете)
NiKo

1
Я думаю, что стоит упомянуть, что параметр rest является новым ECMA 6th ( developer.mozilla.org/en/docs/Web/JavaScript/Reference/… )
Geza Turi

18

В этом случае я рекомендую использовать чистый JavaScript , также в JavaScript нет метода вставки, но у нас есть метод, который является встроенным методом Array, который выполняет эту работу за вас, он называется splice ...

Посмотрим, что такое склейка () ...

Метод splice () изменяет содержимое массива, удаляя существующие элементы и / или добавляя новые элементы.

Хорошо, представьте, что у нас есть этот массив ниже:

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

Мы можем удалить 3так:

arr.splice(arr.indexOf(3), 1);

Он вернет 3, но если мы проверим arr сейчас, мы имеем:

[1, 2, 4, 5]

Пока все хорошо, но как мы можем добавить новый элемент в массив, используя соединение? Давайте вернем 3 в обр ...

arr.splice(2, 0, 3);

Посмотрим, что мы сделали ...

Мы снова используем splice , но на этот раз для второго аргумента мы передаем 0 , что означает, что мы не хотим удалять элемент, но в то же время мы добавляем третий аргумент, который будет 3, который будет добавлен во второй индекс ...

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

arr.splice(2, 2, 3);

Который удалит 2 элемента в индексе 2, затем добавит 3 в индексе 2, и результат будет:

[1, 2, 3, 5];

Это показывает, как работает каждый элемент в соединении:

array.splice (start, deleteCount, item1, item2, item3 ...)


13

Добавить отдельный элемент по определенному индексу

//Append at specific position(here at index 1)
arrName.splice(1, 0,'newName1');
//1: index number, 0: number of element to remove, newName1: new element


//Append at specific position (here at index 3)
arrName[3] = 'newName1';

Добавить несколько элементов по определенному индексу

//Append from index number 1
arrName.splice(1, 0,'newElemenet1', 'newElemenet2', 'newElemenet3');
//1: index number from where append start, 
//0: number of element to remove, 
//newElemenet1,2,3: new elements

8
Стоит отметить, что arrName [3] не добавляет, он переопределяет.
Сфратини

Он добавляет элемент в существующий массив без перегрузки, например: let arrName = ['xxx', 'yyy', 'zzz']; arrName.splice (1, 0, «aaa», «bbb», «ccc»); после распечатки arrName
Срикрушна

Если arrName содержит более 3 элементов, вы переопределяете третий, а не добавляете. Или я смотрю на это неправильно?
Сфратини

Если мы вставим элемент в середину, он сместит следующий элемент, а не оверид. Пожалуйста, укажите вашу проблему, что вам нужно. Возьмите массив (пример) и что вам нужно на выходе. Пожалуйста, прокомментируйте меня
Srikrushna

1
@Srikrushna добавится arrName[3] = 'newName1';, если в массиве всего 3 элемента. Если в индексе 3 есть элемент, он будет заменен. Если вы хотите добавить в конце, лучше использоватьarrName.push('newName1');
трепет

6

Другое возможное решение, с использованием Array#reduce.

var arr = ["apple", "orange", "raspberry"],
    arr2 = [1, 2, 4];

function insert(arr, item, index) {
    arr = arr.reduce(function(s, a, i) {
      i == index ? s.push(item, a) : s.push(a);
      return s;
    }, []);   
    console.log(arr);
}

insert(arr, "banana", 1);
insert(arr2, 3, 2);


6

Вот два способа:

const array = [ 'My', 'name', 'Hamza' ];

array.splice(2, 0, 'is');

console.log("Method 1 : ", array.join(" "));

ИЛИ

Array.prototype.insert = function ( index, item ) {
    this.splice( index, 0, item );
};

const array = [ 'My', 'name', 'Hamza' ];
array.insert(2, 'is');

console.log("Method 2 : ", array.join(" "));


4

Хотя на этот вопрос уже дан ответ, я добавляю эту заметку для альтернативного подхода.

Я хотел поместить известное количество элементов в массив, в определенные позиции, так как они выходят из «ассоциативного массива» (то есть объекта), который по определению не гарантированно находится в отсортированном порядке. Я хотел, чтобы результирующий массив был массивом объектов, но объекты должны быть в определенном порядке в массиве, так как массив гарантирует их порядок. Я так и сделал.

Сначала исходный объект, строка JSONB, полученная из PostgreSQL. Я хотел отсортировать его по свойству order в каждом дочернем объекте.

var jsonb_str = '{"one": {"abbr": "", "order": 3}, "two": {"abbr": "", "order": 4}, "three": {"abbr": "", "order": 5}, "initialize": {"abbr": "init", "order": 1}, "start": {"abbr": "", "order": 2}}';

var jsonb_obj = JSON.parse(jsonb_str);

Поскольку число узлов в объекте известно, я сначала создаю массив с указанной длиной:

var obj_length = Object.keys(jsonb_obj).length;
var sorted_array = new Array(obj_length);

А затем выполните итерацию объекта, поместив вновь созданные временные объекты в нужные места в массиве без какой-либо «сортировки».

for (var key of Object.keys(jsonb_obj)) {
  var tobj = {};
  tobj[key] = jsonb_obj[key].abbr;

  var position = jsonb_obj[key].order - 1;
  sorted_array[position] = tobj;
}

console.dir(sorted_array);

3

Любой, у кого все еще есть проблемы с этим и попробовал все варианты выше и никогда не получил это. Я поделюсь своим решением, это принять во внимание, что вы не хотите явно указывать свойства вашего объекта против массива.

function isIdentical(left, right){
    return JSON.stringify(left) === JSON.stringify(right);
}

function contains(array, obj){
    let count = 0;
    array.map((cur) => {
          if(this.isIdentical(cur, obj)) count++;
    });
    return count > 0;
}

Это комбинация итерации ссылочного массива и сравнения его с объектом, который вы хотите проверить, преобразовать их оба в строку, а затем повторить, если она совпадает. Тогда вы можете просто посчитать. Это можно улучшить, но это то, где я остановился. Надеюсь это поможет.


3

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

function insert(arr, val, index) {
    return index >= arr.length 
        ? arr.concat(val)
        : arr.reduce((prev, x, i) => prev.concat(i === index ? [val, x] : x), []);
}

Таким образом, таким образом мы можем вернуть новый массив (это будет классный функциональный способ - гораздо лучше, чем использовать push или splice) с элементом, вставленным в index, и, если индекс больше длины массива, он будет вставлен в конце.


3

Array#splice()это путь, если вы действительно не хотите избежать изменения массива. Учитывая 2 массива arr1и arr2, вот как вы должны вставить содержимое arr2в arr1после первого элемента:

const arr1 = ['a', 'd', 'e'];
const arr2 = ['b', 'c'];

arr1.splice(1, 0, ...arr2); // arr1 now contains ['a', 'b', 'c', 'd', 'e']

console.log(arr1)

Если вас беспокоит изменение массива (например, при использовании Immutable.js), вы можете вместо этого использовать slice(), не путать splice()с a 'p'.

const arr3 = [...arr1.slice(0, 1), ...arr2, ...arr1.slice(1)];

2

Я попробовал это, и он работает нормально!

var initialArr = ["India","China","Japan","USA"];
initialArr.splice(index, 0, item);

Индекс - это позиция, в которую вы хотите вставить или удалить элемент. 0 т.е. вторые параметры определяют номер элемента из индекса, который будет удален. Элемент - это новые записи, которые вы хотите сделать в массиве. Это может быть один или несколько.

initialArr.splice(2, 0, "Nigeria");
initialArr.splice(2, 0, "Australia","UK");

4
просто скопируйте и вставьте ответ выше. это не добавляет никакой ценности к вопросу. либо вы добавляете новый ответ, либо комментируете существующий. пожалуйста, попробуйте внести что-то новое. мы не хотим портить это сообщество
Ханнад Рехман

1

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

Это проверяет, если пункт выхода

let ifExist = (item, strings = [ '' ], position = 0) => {
     // output into an array with empty string. Important just in case their is no item. 
    let output = [ '' ];
    // check to see if the item that will be positioned exist.
    if (item) {
        // output should equal to array of strings. 
        output = strings;
       // use splice in order to break the array. 
       // use positition param to state where to put the item
       // and 0 is to not replace an index. Item is the actual item we are placing at the prescribed position. 
        output.splice(position, 0, item);
    }
    //empty string is so we do not concatenate with comma or anything else. 
    return output.join("");
};

И тогда я называю это ниже.

ifExist("friends", [ ' ( ', ' )' ], 1)}  // output: ( friends )
ifExist("friends", [ ' - '], 1)}  // output:  - friends 
ifExist("friends", [ ':'], 0)}  // output:   friends: 

1

Немного более старая тема, но я должен согласиться с Реду выше, потому что у splice определенно немного запутанный интерфейс. И ответ, данный cdbajorin, что «он возвращает пустой массив только тогда, когда второй параметр равен 0. Если он больше 0, он возвращает элементы, удаленные из массива», является точным доказательством этого. Функция предназначена для соединения или, как уже было сказано ранее, Якоба Келлера, «для присоединения или подключения, а также для изменения. У вас есть установленный массив, который вы сейчас изменяете, который включает добавление или удаление элементов…». Учитывая это, возвращаемое значение элементов, если они были удалены, в лучшем случае неудобно. И я на 100% согласен, что этот метод мог бы лучше подходить для цепочки, если бы он возвратил то, что кажется естественным, новый массив с добавленными элементами сращивания. Затем вы можете делать что-то вроде ["19", "17"]. Splice (1,0, "18"). Join ("...") или что угодно с возвращаемым массивом. Тот факт, что он возвращает то, что было удалено, является просто бессмысленным ИМХО. Если целью метода было «вырезать набор элементов», и это было только его намерением, может быть. Похоже, если я не знаю, что я уже вырезал, у меня, вероятно, нет особых причин вырезать эти элементы, не так ли? Было бы лучше, если бы он вел себя как concat, map, Reduce, Slice и т. Д., Где новый массив сделан из существующего массива, а не изменял существующий массив. Все они цепные, и это серьезная проблема. Это довольно распространенное явление для манипулирования массивами. Похоже, что язык должен идти в ту или иную сторону и стараться придерживаться его как можно больше. Javascript, будучи функциональным и менее декларативным, просто кажется странным отклонением от нормы.


-2

Представление

Сегодня (2020.04.24) я выполняю тесты для выбранных решений для больших и маленьких массивов. Я тестировал их на MacOs High Sierra 10.13.6 на Chrome 81.0, Safari 13.1, Firefox 75.0.

Выводы

Для всех браузеров

  • неожиданно для небольших массивов решения на месте на основе sliceи reduce(D, E, F) обычно в 10-100 раз быстрее, чем решения на месте
  • для больших массивов решения на основе splice(AI, BI, CI) были самыми быстрыми (иногда ~ 100x - но это зависит от размера массива)
  • для небольших массивов решение BI было самым медленным
  • для больших массивов E решение было самым медленным

введите описание изображения здесь

подробности

Тесты были разделены на две группы: решения на месте (AI, BI, CI) и решения не на месте (D, E, F) и выполнялись для двух случаев.

  • тест для массива с 10 элементами - вы можете запустить его ЗДЕСЬ
  • тест для массива с 1.000.000 элементов - вы можете запустить его ЗДЕСЬ

Протестированный код представлен в следующем фрагменте

Пример результатов для маленького массива на Chrome ниже

введите описание изображения здесь

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.