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

avatar
tags2k
25 февраля 2009 в 14:29
2696021
25
3679

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

arr.insert(index, item)

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

Источник
Domino
18 февраля 2015 в 15:36
132

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

Tim
14 апреля 2016 в 08:14
29

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

Victor
7 мая 2018 в 13:31
7

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

Tim
8 мая 2018 в 06:17
5

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

noobie
1 октября 2018 в 05:48
2

Кроме того, см. это, для извращенного сюрприза (:

Andrew
7 июня 2020 в 00:14
0

Меня раздражает, что заголовок этого вопроса и заголовок его страницы отличаются (jQuery против JS). По-разному отображается в результатах поиска.

Ответы (25)

avatar
tvanfosson
25 февраля 2009 в 14:32
5952

Вам нужна функция splice для собственного объекта массива.

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

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

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

console.log(arr.join()); // Jani,Hege,Stale,Kai Jim,Borge
arr.splice(2, 0, "Lene");
console.log(arr.join()); // Jani,Hege,Lene,Stale,Kai Jim,Borge
tags2k
25 февраля 2009 в 14:46
228

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

Christoph
25 февраля 2009 в 14:53
102

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

Dingo
10 марта 2011 в 09:54
18

документ: developer.mozilla.org/en/JavaScript/Guide/…

EBarr
13 мая 2014 в 01:45
70

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

Jakub Keller
21 ноября 2014 в 15:45
21

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

tonix
24 октября 2015 в 20:56
1

Может ли кто-нибудь сказать мне, с точки зрения производительности, хорошо ли использовать splice в этом случае? Я имею в виду, если у меня есть массив с тысячами элементов, и я хочу вставить элемент где-то между двумя элементами, как JavaScript обновит индексы массива с той точки, где я вставляю элемент, до конца массива?

tvanfosson
24 октября 2015 в 22:17
0

@tonix Я бы подумал, что это будет операция O (n), поскольку она должна сдвинуть все значения, принадлежащие индексам, следующим за вставленными элементами. В худшем случае (вставка элемента в начале) это будут все (n) элементов в массиве.

tonix
24 октября 2015 в 22:23
0

Я понимаю. Можно ли его как-то улучшить? Я имею в виду, я только что нашел что-то вроде creating two separate indexes placed in the middle of the array или rotating arrays, но я не понял, что имел в виду автор статьи (gamealchemist.wordpress.com/2013/05/01/…) , точка 6 в конце и 7

tvanfosson
24 октября 2015 в 22:33
0

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

ArtOfWarfare
1 июня 2016 в 02:36
0

@tonix - У вас есть реальная проблема с производительностью? Если нет, вы выполняете преждевременную оптимизацию, что приводит к усложнению поддержки кода без какой-либо пользы. Обеспечение хорошей работы сращивания является обязанностью человека, пишущего движок/библиотеку Javascript, а не вашей. Не делайте это своим, если вам не нужно (IE, ваша программа неприемлемо медленная, если у вас нет уродливых хаков.)

tonix
3 июня 2016 в 06:57
0

@ArtOfWarfare Как сказал Тванфоссон, количество операций сращивания составляет O(n). Тем временем я создал класс, который я назвал LinkedOrderedMap, который позволяет мне вставлять элементы и сохранять их в порядке, а когда мне нужно удалить элемент из списка, я просто отключаю узел, в котором элемент находится внутри списка. list и сообщить предыдущему узлу, что его следующий элемент теперь является следующим узлом узла, который я собираюсь удалить. Чтобы вставить элемент между другими элементами в списке, я также могу использовать ту же стратегию.

tonix
3 июня 2016 в 06:59
0

@ArtOfWarfare Конечно, мне нужно сравнить его, прежде чем я смогу сделать предположения о приросте производительности, но при такой реализации количество требуемых операций постоянно. Неважно, насколько длинный список. Я помню, что был онлайн-сайт, где вы можете сравнить свой код JS, но я не мог вспомнить название. Не могли бы вы дать мне ссылку, если вы ее знаете. Затем я сравним написанный мной код с splice и сообщу, каковы результаты.

ArtOfWarfare
3 июня 2016 в 12:19
0

@tonix - Ваш код написан на JavaScript и нуждается в интерпретации. Код Splice, вероятно, более родной.

tonix
4 июня 2016 в 11:03
0

@ArtOfWarfare Да, я знаю. Но мне все равно любопытно сделать тест. Я просто не помню название сайта, где вы тестируете код JS...

tetris11
23 сентября 2016 в 17:55
2

учитывая, что новые элементы class и constructor для нового EMCAScript являются не чем иным, как синтаксическим сахаром для существующих методов, не будет ли слишком сложно создать функцию/псевдоним insert?

Konrad Viltersten
25 января 2020 в 21:53
0

Там должен Определенно Быть синтаксическим сахаром, как Вставка (что, где) или insertat (что, где) , предпочтительно с где установлен на последний индекс по умолчанию.

Bitterblue
2 ноября 2020 в 10:48
0

Splice был преждевременной оптимизацией, когда «изобрели» JavaScript. Вместо того, чтобы просто добавить обычное «вставить/удалить», они взяли функцию склеивания, которая делает и то, и другое и причиняет боль каждому новичку. Сейчас все привыкли сплайсить и со мной не согласятся.

user14860400
12 января 2021 в 06:29
0

Сращивание сначала удаляет элементы (второй параметр), а затем вставляет новые элементы (третий и другие параметры). Splice очень полезен, когда вы собираетесь работать с массивом javascript.

Broda Noel
4 мая 2021 в 18:24
0

16 лет работает разработчиком. Около 12 лет работы с JS. И я до сих пор не могу вспомнить, как "протолкнуть элемент с помощью индекса". Очередной провал для JS.

Nate Thompson
13 мая 2021 в 19:36
0

Есть ли определенные критерии, по которым вы бы соединили вместо просто array[index] = newValue?

SIMBIOSIS surl
5 августа 2021 в 03:09
0

Я был бы признателен, если бы кто-нибудь мог помочь мне с соответствующим вопросом, который я разместил, но не получил удовлетворительного ответа. Это ссылка (coderhelper.com/questions/68612472/…). Заранее спасибо.

avatar
Pikamander2
13 марта 2022 в 08:29
1

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

function add_items_to_array_at_position(array, index, new_items)
{
    return [...array.slice(0, index), ...new_items, ...array.slice(index)];
}

Пример использования:

let old_array = [1,2,5];

let new_array = add_items_to_array_at_position(old_array, 2, [3,4]);

console.log(new_array);

//Output: [1,2,3,4,5]
Pikamander2
13 марта 2022 в 08:33
0

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

avatar
bmaggi
14 января 2022 в 01:42
0

Я делаю так:

const insert = (what, where, index) => 
  ([...where.slice(0, index), what , ...where.slice(index, where.length)]);

const insert = (what, where, index) =>
  ([...where.slice(0, index), what , ...where.slice(index, where.length)]);
  
const list = [1, 2, 3, 4, 5, 6];
const newList = insert('a', list, 2);

console.log(newList.indexOf('a') === 2);
avatar
Gass
6 января 2022 в 09:46
2

Метод splice() обычно получает три параметра при добавлении элемента:

  1. индекс массива, куда будет добавлен элемент.
  2. количество удаляемых элементов, в данном случае 0.
  3. Элемент для добавления.

let array = ['item 1', 'item 2', 'item 3'],
    insertAtIndex = 0,
    itemsToRemove = 0;
    
array.splice(insertAtIndex, itemsToRemove, 'insert this string on index 0');

console.log(array);
avatar
Ran Turner
18 декабря 2021 в 17:11
3

Использование Array.prototype.splice() — простой способ добиться этого

const numbers = ['one', 'two', 'four', 'five']
numbers.splice(2, 0, 'three');

console.log(numbers)

Подробнее о Array.prototype.splice() здесь

avatar
Baptiste Arnaud
13 декабря 2021 в 10:39
0

Вот современный (функциональный Typescript) способ:

export const insertItemInList = <T>(
  arr: T[],
  index: number,
  newItem: T
): T[] => [...arr.slice(0, index), newItem, ...arr.slice(index)]
avatar
hossein sedighian
8 октября 2020 в 22:26
5

Мне нравится немного безопасности, и я использую это:

   Array.prototype.Insert = function (item, before) {
        if (!item) return;
        if (before == null || before < 0 || before > this.length - 1) {
            this.push(item);
            return;
        }
        this.splice(before, 0,item );
    }
    
    
   var t = ["a","b"]
   
   t.Insert("v",1)
    
    console.log(t )
blazkovicz
11 января 2021 в 13:01
4

Вы сказали, что вам нравится безопасность, а затем предлагаете изменить базовый прототип! логика? нет

hossein sedighian
27 января 2021 в 05:00
2

да .. это мое определение безопасности .. лол

avatar
kabirbaidhya
12 сентября 2020 в 06:37
8

Неизменная вставка

Использование метода splice, безусловно, лучший ответ, если вам нужно вставить в массив на месте.

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

function insert(array, index) {
  const items = Array.prototype.slice.call(arguments, 2);

  return [].concat(array.slice(0, index), items, array.slice(index));
}

const list = ['one', 'two', 'three'];

const list1 = insert(list, 0, 'zero'); // Insert single item
const list2 = insert(list, 3, 'four', 'five', 'six'); // Insert multiple

console.log('Original list: ', list);
console.log('Inserted list1: ', list1);
console.log('Inserted list2: ', list2);

Примечание: Это предварительный ES6 способ сделать это, поэтому он работает как для старых, так и для новых браузеров.

Если вы используете ES6, вы также можете попробовать остальные параметры; см. этот ответ.

avatar
Kamil Kiełczewski
24 апреля 2020 в 11:07
30

Решения и производительность

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

Выводы

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

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

Enter image description here

Подробности

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

  • тест для массива из 10 элементов - вы можете запустить его здесь
  • тест для массива из 1 000 000 элементов - вы можете запустить его здесь

Протестированный код представлен в приведенном ниже фрагменте:

jsfiddle

function AI(arr, i, el) {
  arr.splice(i, 0, el);
  return arr;
}

function BI(arr, i, el) {
  Array.prototype.splice.apply(arr, [i, 0, el]);
  return arr;
}

function CI(arr, i, el) {
  Array.prototype.splice.call(arr, i, 0, el);
  return arr;
}

function D(arr, i, el) {
  return arr.slice(0, i).concat(el, arr.slice(i));
}

function E(arr, i, el) {
  return [...arr.slice(0, i), el, ...arr.slice(i)]
}

function F(arr, i, el) {
  return arr.reduce((s, a, j)=> (j-i ? s.push(a) : s.push(el, a), s), []);
}



// -------------
// TEST
// -------------

let arr = ["a", "b", "c", "d", "e", "f"];

let log = (n, f) => {
  let a = f([...arr], 3, "NEW");
  console.log(`${n}: [${a}]`);
};

log('AI', AI);
log('BI', BI);
log('CI', CI);
log('D', D);
log('E', E);
log('F', F);
This snippet only presents tested code (it not perform tests)

Примеры результатов для небольшого массива в Google Chrome приведены ниже:

Enter image description here

kabirbaidhya
12 сентября 2020 в 05:52
4

Ответ не касается вопроса ОП.

Kamil Kiełczewski
12 сентября 2020 в 07:24
19

@kabirbaidhya на самом деле в этом ответе вы можете найти много решений вопроса OP, но дополнительная ценность этого ответа заключается в сравнении их производительности - я надеюсь, что многие люди сочтут это полезным.

kabirbaidhya
12 сентября 2020 в 07:46
1

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

avatar
vkarpov15
23 декабря 2019 в 19:37
15

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() с 'p'.

const arr3 = [...arr1.slice(0, 1), ...arr2, ...arr1.slice(1)];
avatar
M. Hamza Rajput
28 августа 2019 в 09:28
20

Есть два способа:

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(" "));
avatar
meem
18 июля 2019 в 17:38
5

Я должен согласиться с ответом Реду, потому что splice() определенно имеет немного запутанный интерфейс. И ответ, данный cdbajorin, что «он возвращает пустой массив только тогда, когда второй параметр равен 0. Если он больше 0, он возвращает элементы, удаленные из массива», хотя и является точным, подтверждая точку зрения.

Назначение функции состоит в том, чтобы соединять или, как сказал ранее Джейкоб Келлер, "присоединять или соединять, а также изменять".

У вас есть установленный массив, который вы сейчас изменяете, что включает добавление или удаление элементов...." Учитывая это, возвращаемое значение элементов, если таковые имеются, которые были удалены, в лучшем случае неудобны. И я 100% согласитесь, что этот метод мог бы лучше подходить для цепочек, если бы он возвращал то, что кажется естественным, новый массив с добавленными соединенными элементами.Тогда вы могли бы делать такие вещи, как ["19", "17"].splice(1,0, "18").join("...") или что угодно с возвращаемым массивом.

Тот факт, что он возвращает то, что было удалено, является просто ерундой ИМХО. Если целью метода было «вырезать набор элементов» и это было его единственной целью, возможно. Похоже, если я уже не знаю, что я вырезаю, у меня, вероятно, нет причин вырезать эти элементы, не так ли?

Было бы лучше, если бы он вел себя как concat(), map(), reduce(), slice() и т. д., где новый массив создается из существующего массива, а не видоизменяется существующий массив. Все они связаны, и это является серьезной проблемой. Манипуляции с цепочками массивов довольно распространены.

Похоже, что язык должен двигаться в одном или другом направлении и стараться придерживаться его как можно дольше. Поскольку JavaScript функционален и менее декларативен, это кажется странным отклонением от нормы.

avatar
Lesly Revenge
16 февраля 2019 в 22:48
5

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

Это проверяет, существует ли элемент:

let ifExist = (item, strings = [ '' ], position = 0) => {
     // Output into an array with an empty string. Important just in case their isn't any item.
    let output = [ '' ];
    // Check to see if the item that will be positioned exist.
    if (item) {
        // Output should be equal to an array of strings.
        output = strings;
       // Use splice() in order to break the array.
       // Use positional parameters 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:
avatar
alejoko
12 января 2019 в 17:04
7

Фиксация прибыли по методу уменьшения следующим образом:

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) с элементом, вставленным в индекс, и если индекс больше длины массива, он будет вставлен в конец.

avatar
Clyde
6 декабря 2018 в 04:26
7

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

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

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

avatar
Srikrushna
28 июня 2018 в 19:13
20

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

// Append at a 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 a 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
sfratini
10 сентября 2018 в 22:40
10

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

Srikrushna
12 сентября 2018 в 18:49
0

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

sfratini
12 сентября 2018 в 18:51
0

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

Srikrushna
12 сентября 2018 в 18:56
0

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

sfratini
12 сентября 2018 в 20:48
0

У меня нет проблемы, я говорю, что это не добавляется: arrName[3]. Вы переопределяете то, что находится на 4-й позиции.

awe
14 ноября 2019 в 08:24
2

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

Srikrushna
24 декабря 2020 в 06:16
0

@awe Я согласен с вашим комментарием, но вопрос в конкретном индексе, мы должны вставить элементы. На этот вопрос мой ответ правильный

avatar
Alireza
25 декабря 2017 в 13:04
31

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

Давайте посмотрим, что такое splice()...

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

Хорошо, представьте, что у нас есть следующий массив:

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

Мы можем удалить 3 следующим образом:

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

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

[1, 2, 4, 5]

Пока все хорошо, но как мы можем добавить новый элемент в массив с помощью соединения?

Вернем 3 в ряд...

arr.splice(2, 0, 3);

Давайте посмотрим, что мы сделали...

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

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

arr.splice(2, 2, 3);

Что удалит два элемента в индексе 2. Затем добавьте 3 в индексе 2, и результат будет:

[1, 2, 3, 5];

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

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

Cristian E.
9 октября 2020 в 14:47
2

Спасибо за объяснение, в будущем я предлагаю использовать нецифровые числа для значений массива, чтобы показать пример. Например: arr.splice(2, 0, 3) vs arr.splice(2, 0, "C"). Читателю легче понять, какой аргумент отображается в часть значения, а какой — в часть индекса. Спасибо!

avatar
kind user
5 апреля 2017 в 17:06
13

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

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

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

console.log(insert(arr, "banana", 1));
console.log(insert(arr2, 3, 2))
avatar
Pawan
8 марта 2017 в 06:35
6

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

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

Индекс — это позиция, в которую вы хотите вставить или удалить элемент.

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

initialArr.splice(2, 0, "Nigeria");
initialArr.splice(2, 0, "Australia","UK");
hannad rehman
24 октября 2017 в 06:50
4

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

avatar
gafi
4 июля 2016 в 09:18
211

Помимо объединения, вы можете использовать этот подход, который не будет изменять исходный массив, но создаст новый массив с добавленным элементом. Обычно следует избегать мутаций, когда это возможно. Здесь я использую оператор распространения 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]
anotherDev
11 декабря 2017 в 09:32
2

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

gafi
16 декабря 2017 в 22:35
8

@HarshKanchina Вероятно, это потому, что большинство ответов до ES6, но, судя по моему опыту, сейчас этот подход очень распространен.

Jack G
19 января 2021 в 02:19
1

Этот подход всегда будет медленнее и хуже, чем сращивание. Не дайте себя обмануть красивым синтаксисом сахара или популярностью среди других заблудших разработчиков (*кашель* гафи *кашель*). Выделение целого нового массива и отбрасывание старого намного медленнее, чем изменение исходного массива. Если вам нужна копия, позвоните по slice() перед splice(). Никогда не используйте ES6 для таких тривиальных вещей, которые можно сделать намного лучше и чище с помощью других API.

Daniele Testa
25 мая 2021 в 09:34
1

Вы должны объяснить, ПОЧЕМУ вы должны избегать мутаций. Это медленно? Если да, то насколько медленнее? Стоит ли это дополнительных «хлопот»?

nickf
22 сентября 2021 в 09:00
0

@JackG не забывайте, что slice() будет выделять новый массив, и действительно, splice() также выделяет новый массив, поскольку он возвращает массив удаленных элементов (в данном случае пустой массив). Запуск теста для этих случаев показывает, что вставка выполняется быстрее (примерно на 30%), но мы находимся в диапазоне миллионов операций в секунду, поэтому, если ваше приложение не выполняет множество этих операций в тугая петля, это не будет иметь никакого значения.

Jack G
22 сентября 2021 в 20:53
0

@nickf Если вы объединяете небольшое количество элементов (особенно нулевых элементов), то небольшой массив, выделенный объединением, будет частью молодого поколения, которое представляет собой память с почти нулевой стоимостью. Для сравнения, создание копии большого массива будет использовать не новое пространство, а специальное пространство больших объектов, возможно, даже вызывая системный вызов для выделения большего объема памяти, если массив достаточно велик. Только в конкретном случае сращивания большая часть очень большого массива может сращиваться медленнее.

avatar
Redu
13 мая 2016 в 23:22
35

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

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));
chrisbajorin
22 мая 2016 в 21:15
4

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

Redu
22 мая 2016 в 21:23
0

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

NiKo
2 июня 2016 в 14:18
1

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

Geza Turi
9 декабря 2016 в 17:02
1

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

avatar
Ville
4 декабря 2015 в 18:36
9

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

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

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

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);
avatar
VisioN
25 марта 2013 в 17:45
84

Пользовательский массив 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"

DEMO: http://jsfiddle.net/UPphH/

Nolo
30 марта 2013 в 23:56
0

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

Alexis Wilke
12 декабря 2014 в 02:03
0

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

Alexis Wilke
12 декабря 2014 в 02:08
0

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

VisioN
12 декабря 2014 в 08:46
0

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

Corné
26 июня 2020 в 03:08
0

По какой-то причине, когда я использую вставку2, я получаю исключение «Ожидается 1 аргумент, но получено 2».

avatar
FrEsC 81
3 октября 2012 в 14:26
358

Метод 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' ]
Ryan Smith
30 мая 2014 в 12:15
14

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

rep_movsd
2 июля 2014 в 09:38
7

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

marsze
21 августа 2018 в 09:48
15

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

Luis Cabrera Benito
19 февраля 2019 в 18:09
61

Не изменяйте объекты, которыми вы не владеете

Solomon Ucko
5 мая 2019 в 02:39
1

@RyanSmith Или, с ES6, Array.prototype.insert = function(index, ...items) { this.splice.call(this, index, 0, ...items); }.

Ryan Smith
9 мая 2019 в 20:13
1

@SolomonUcko, да, вы могли бы использовать ES6, я бы просто сделал [...arr.slice(0, index), ...items, ...arr.slice(index)]

Solomon Ucko
9 мая 2019 в 20:14
0

@RyanSmith Проблема в том, что нужно копировать начало массива, а не только конец.

Ryan Smith
11 мая 2019 в 07:18
1

@SolomonUcko, это правда, если вы работаете с большими массивами, это следует учитывать. Я думаю, что для небольших массивов преимущества неизменности перевешивают незначительные последствия для производительности. Обратите внимание, что здесь есть ответ, в котором используется этот подход coderhelper.com/a/38181008/1221906, поэтому, вероятно, лучше всего оставить отзыв для людей, которые используют этот подход.

satya164
31 мая 2019 в 12:54
17

Не изменяйте прототипы

avatar
Luis Perez
30 августа 2012 в 04:37
52

Если вы хотите вставить несколько элементов в массив одновременно, ознакомьтесь с этим ответом 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);
Matt Sach
10 сентября 2012 в 16:12
2

Не лучше ли для функции insertAt() вызвать метод insertArrayAt() после того, как он создал одноэлементный массив arrayToInsert? Это позволяет избежать повторения идентичного кода.

CRice
29 января 2015 в 00:44
1

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

CRice
29 января 2015 в 00:56
0

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