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

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

arr.insert(index, item)

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

Ответов (20)

Решение

Вам нужна 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

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

Вы можете реализовать 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' ]

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

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

Сначала исходный объект, строка 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);

Для правильного функционального программирования и создания цепочек необходимо изобретение 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));

Помимо сращивания, вы можете использовать этот подход, который не будет изменять исходный массив, но создаст новый массив с добавленным элементом. Обычно по возможности следует избегать мутаций. Я использую здесь оператор распространения 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]

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

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

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

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

Другое возможное решение, с использованием 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))

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

//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

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

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

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

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

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

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

Это проверяет, выходит ли элемент

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: 

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

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

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(" "));

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)];

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

   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 )

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

Сегодня (24.04.2020) я провожу тесты выбранных решений для больших и малых массивов. Я тестировал их на 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 элементов - вы можете запустить его ЗДЕСЬ

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

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)

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

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

Если вы хотите вставить сразу несколько элементов в массив, ознакомьтесь с этим ответом на переполнение стека: лучший способ объединить массив в массив в 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);

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

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

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

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

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

Убрать можно 3 так:

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

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

[1, 2, 4, 5]

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

arr.splice(2, 0, 3);

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

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

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

arr.splice(2, 2, 3);

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

[1, 2, 3, 5];

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

array.splice (начало, deleteCount, элемент1, элемент2, элемент3 ...)

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

С использованием 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);

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

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