Я ищу метод вставки массива JavaScript в стиле:
arr.insert(index, item)
Предпочтительно в jQuery, но на данном этапе подойдет любая реализация JavaScript.
Я ищу метод вставки массива JavaScript в стиле:
arr.insert(index, item)
Предпочтительно в jQuery, но на данном этапе подойдет любая реализация JavaScript.
Вам нужна функция 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: потому что функция делает больше, чем просто вставляет элементы, и ее имя уже установлено в Perl?
Сращивание может вставляться, но столь же часто не. Например: arr.splice(2,3)
удалит 3 элемента, начиная с индекса 2. Без передачи 3-го....N-го параметра ничего не будет вставлено. Так что имя insert()
тоже не соответствует действительности.
Я думаю, что термин «сращивание» имеет смысл. Сращивание означает присоединение или соединение, а также изменение. У вас есть установленный массив, который вы сейчас «меняете», что включает добавление или удаление элементов. Вы указываете, где в массиве начать, затем сколько старых элементов удалить (если есть) и, наконец, при необходимости список новых элементов для добавления. Splice — это, конечно, также отличный научно-фантастический термин.
Может ли кто-нибудь сказать мне, с точки зрения производительности, хорошо ли использовать splice
в этом случае? Я имею в виду, если у меня есть массив с тысячами элементов, и я хочу вставить элемент где-то между двумя элементами, как JavaScript обновит индексы массива с той точки, где я вставляю элемент, до конца массива?
@tonix Я бы подумал, что это будет операция O (n), поскольку она должна сдвинуть все значения, принадлежащие индексам, следующим за вставленными элементами. В худшем случае (вставка элемента в начале) это будут все (n) элементов в массиве.
Я понимаю. Можно ли его как-то улучшить? Я имею в виду, я только что нашел что-то вроде creating two separate indexes placed in the middle of the array
или rotating arrays
, но я не понял, что имел в виду автор статьи (gamealchemist.wordpress.com/2013/05/01/…) , точка 6 в конце и 7
Я думаю, что он говорит о методах, позволяющих избежать изменения размера массива, самостоятельно отслеживая действительные индексы. Если в настоящее время вы не сталкиваетесь с проблемой производительности, я бы не стал пытаться писать свои собственные параметры массива. Также возможно, что другая структура данных может работать лучше, например сбалансированные деревья, в зависимости от потребностей вашего приложения.
@tonix - У вас есть реальная проблема с производительностью? Если нет, вы выполняете преждевременную оптимизацию, что приводит к усложнению поддержки кода без какой-либо пользы. Обеспечение хорошей работы сращивания является обязанностью человека, пишущего движок/библиотеку Javascript, а не вашей. Не делайте это своим, если вам не нужно (IE, ваша программа неприемлемо медленная, если у вас нет уродливых хаков.)
@ArtOfWarfare Как сказал Тванфоссон, количество операций сращивания составляет O(n)
. Тем временем я создал класс, который я назвал LinkedOrderedMap
, который позволяет мне вставлять элементы и сохранять их в порядке, а когда мне нужно удалить элемент из списка, я просто отключаю узел, в котором элемент находится внутри списка. list и сообщить предыдущему узлу, что его следующий элемент теперь является следующим узлом узла, который я собираюсь удалить. Чтобы вставить элемент между другими элементами в списке, я также могу использовать ту же стратегию.
@ArtOfWarfare Конечно, мне нужно сравнить его, прежде чем я смогу сделать предположения о приросте производительности, но при такой реализации количество требуемых операций постоянно. Неважно, насколько длинный список. Я помню, что был онлайн-сайт, где вы можете сравнить свой код JS, но я не мог вспомнить название. Не могли бы вы дать мне ссылку, если вы ее знаете. Затем я сравним написанный мной код с splice и сообщу, каковы результаты.
@tonix - Ваш код написан на JavaScript и нуждается в интерпретации. Код Splice, вероятно, более родной.
@ArtOfWarfare Да, я знаю. Но мне все равно любопытно сделать тест. Я просто не помню название сайта, где вы тестируете код JS...
учитывая, что новые элементы class
и constructor
для нового EMCAScript являются не чем иным, как синтаксическим сахаром для существующих методов, не будет ли слишком сложно создать функцию/псевдоним insert
?
Там должен Определенно Быть синтаксическим сахаром, как Вставка (что, где) или insertat (что, где) , предпочтительно с где установлен на последний индекс по умолчанию.
Splice был преждевременной оптимизацией, когда «изобрели» JavaScript. Вместо того, чтобы просто добавить обычное «вставить/удалить», они взяли функцию склеивания, которая делает и то, и другое и причиняет боль каждому новичку. Сейчас все привыкли сплайсить и со мной не согласятся.
Сращивание сначала удаляет элементы (второй параметр), а затем вставляет новые элементы (третий и другие параметры). Splice очень полезен, когда вы собираетесь работать с массивом javascript.
16 лет работает разработчиком. Около 12 лет работы с JS. И я до сих пор не могу вспомнить, как "протолкнуть элемент с помощью индекса". Очередной провал для JS.
Есть ли определенные критерии, по которым вы бы соединили вместо просто array[index] = newValue
?
Я был бы признателен, если бы кто-нибудь мог помочь мне с соответствующим вопросом, который я разместил, но не получил удовлетворительного ответа. Это ссылка (coderhelper.com/questions/68612472/…). Заранее спасибо.
Вот простая функция, поддерживающая одновременную вставку нескольких значений:
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]
Это похоже на многие из существующих ответов, но с кратким сочетанием функции/оператора распространения/нескольких элементов/примера/вывода, которые еще не были опубликованы.
Я делаю так:
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);
Метод splice()
обычно получает три параметра при добавлении элемента:
0
.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);
Использование Array.prototype.splice()
— простой способ добиться этого
const numbers = ['one', 'two', 'four', 'five']
numbers.splice(2, 0, 'three');
console.log(numbers)
Подробнее о Array.prototype.splice()
здесь
Вот современный (функциональный Typescript) способ:
export const insertItemInList = <T>(
arr: T[],
index: number,
newItem: T
): T[] => [...arr.slice(0, index), newItem, ...arr.slice(index)]
Мне нравится немного безопасности, и я использую это:
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 )
Вы сказали, что вам нравится безопасность, а затем предлагаете изменить базовый прототип! логика? нет
да .. это мое определение безопасности .. лол
Использование метода 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, вы также можете попробовать остальные параметры; см. этот ответ.
Сегодня (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 - но это зависит от размера массива)Тесты были разделены на две группы: решения на месте (AI, BI и CI) и решения не на месте (D, E и F) и проводились для двух случаев:
Протестированный код представлен в приведенном ниже фрагменте:
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 приведены ниже:
Ответ не касается вопроса ОП.
@kabirbaidhya на самом деле в этом ответе вы можете найти много решений вопроса OP, но дополнительная ценность этого ответа заключается в сравнении их производительности - я надеюсь, что многие люди сочтут это полезным.
Возможно, вы захотите немного изменить структуру своего ответа, чтобы пользователи могли сначала увидеть возможные решения, а затем их влияние на производительность. Выглядит в первую очередь ориентированным на производительность рп.
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)];
Есть два способа:
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(" "));
Я должен согласиться с ответом Реду, потому что splice() определенно имеет немного запутанный интерфейс. И ответ, данный cdbajorin, что «он возвращает пустой массив только тогда, когда второй параметр равен 0. Если он больше 0, он возвращает элементы, удаленные из массива», хотя и является точным, подтверждая точку зрения.
Назначение функции состоит в том, чтобы соединять или, как сказал ранее Джейкоб Келлер, "присоединять или соединять, а также изменять".
У вас есть установленный массив, который вы сейчас изменяете, что включает добавление или удаление элементов...." Учитывая это, возвращаемое значение элементов, если таковые имеются, которые были удалены, в лучшем случае неудобны. И я 100% согласитесь, что этот метод мог бы лучше подходить для цепочек, если бы он возвращал то, что кажется естественным, новый массив с добавленными соединенными элементами.Тогда вы могли бы делать такие вещи, как ["19", "17"].splice(1,0, "18").join("...") или что угодно с возвращаемым массивом.
Тот факт, что он возвращает то, что было удалено, является просто ерундой ИМХО. Если целью метода было «вырезать набор элементов» и это было его единственной целью, возможно. Похоже, если я уже не знаю, что я вырезаю, у меня, вероятно, нет причин вырезать эти элементы, не так ли?
Было бы лучше, если бы он вел себя как concat(), map(), reduce(), slice() и т. д., где новый массив создается из существующего массива, а не видоизменяется существующий массив. Все они связаны, и это является серьезной проблемой. Манипуляции с цепочками массивов довольно распространены.
Похоже, что язык должен двигаться в одном или другом направлении и стараться придерживаться его как можно дольше. Поскольку JavaScript функционален и менее декларативен, это кажется странным отклонением от нормы.
Вот работающая функция, которую я использую в одном из своих приложений.
Это проверяет, существует ли элемент:
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:
Фиксация прибыли по методу уменьшения следующим образом:
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) с элементом, вставленным в индекс, и если индекс больше длины массива, он будет вставлен в конец.
Все, у кого все еще есть проблемы с этим, кто перепробовал все варианты в предыдущих ответах и так и не получил его. Я делюсь своим решением, и это нужно учитывать, что вы не хотите явно указывать свойства вашего объекта по сравнению с массивом.
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;
}
Это комбинация итерации массива ссылок и сравнения его с объектом, который вы хотите проверить, преобразования их обоих в строку, а затем итерации, если они совпадают. Тогда можно просто считать. Это можно улучшить, но я остановился на этом.
Добавить один элемент по определенному индексу
// 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
Стоит отметить, что arrName[3] не добавляется, а переопределяет.
Он добавляет элемент в существующий массив без переопределения, например: let arrName = ['xxx', 'yyy', 'zzz']; arrName.splice(1, 0, 'aaa', 'bbb', 'ccc'); после печати arrName
Если arrName имеет более 3 элементов, вы переопределяете 3-й, а не добавляете. Или я смотрю на это неправильно?
Если мы вставляем элемент посередине, он сдвигает следующий элемент, а не переопределяет его. Пожалуйста, укажите вашу проблему, что вам нужно. Возьмите массив (пример) и то, что вам нужно на выходе. пожалуйста, прокомментируйте меня
У меня нет проблемы, я говорю, что это не добавляется: arrName[3]. Вы переопределяете то, что находится на 4-й позиции.
@Srikrushna arrName[3] = 'newName1';
добавит, если в массиве всего 3 элемента. Если в индексе 3 есть элемент, он будет заменен. Если вы хотите добавить в конец, лучше использовать arrName.push('newName1');
@awe Я согласен с вашим комментарием, но вопрос в конкретном индексе, мы должны вставить элементы. На этот вопрос мой ответ правильный
В этом случае я рекомендую использовать чистый 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...)
Спасибо за объяснение, в будущем я предлагаю использовать нецифровые числа для значений массива, чтобы показать пример. Например: arr.splice(2, 0, 3) vs arr.splice(2, 0, "C"). Читателю легче понять, какой аргумент отображается в часть значения, а какой — в часть индекса. Спасибо!
Другое возможное решение с использованием 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))
Я попробовал это, и все работает нормально!
var initialArr = ["India","China","Japan","USA"];
initialArr.splice(index, 0, item);
Индекс — это позиция, в которую вы хотите вставить или удалить элемент.
0, т.е. второй параметр, определяет количество удаляемых элементов из индекса.
item
содержит новые записи, которые вы хотите внести в массив. Это может быть один или несколько.
initialArr.splice(2, 0, "Nigeria");
initialArr.splice(2, 0, "Australia","UK");
просто скопируйте и вставьте ответ выше. это не добавляет никакой ценности вопросу. либо вы добавляете новый ответ, либо комментируете существующий. пожалуйста, попробуйте внести что-то новое. мы не хотим портить это сообщество
Помимо объединения, вы можете использовать этот подход, который не будет изменять исходный массив, но создаст новый массив с добавленным элементом. Обычно следует избегать мутаций, когда это возможно. Здесь я использую оператор распространения 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]
Это хороший и безопасный способ сделать это? Я спрашиваю, потому что это кажется таким элегантным и кратким, но никакие другие ответы не касаются этого. Большинство из них модифицируют объект-прототип!
@HarshKanchina Вероятно, это потому, что большинство ответов до ES6, но, судя по моему опыту, сейчас этот подход очень распространен.
Этот подход всегда будет медленнее и хуже, чем сращивание. Не дайте себя обмануть красивым синтаксисом сахара или популярностью среди других заблудших разработчиков (*кашель* гафи *кашель*). Выделение целого нового массива и отбрасывание старого намного медленнее, чем изменение исходного массива. Если вам нужна копия, позвоните по slice()
перед splice()
. Никогда не используйте ES6 для таких тривиальных вещей, которые можно сделать намного лучше и чище с помощью других API.
Вы должны объяснить, ПОЧЕМУ вы должны избегать мутаций. Это медленно? Если да, то насколько медленнее? Стоит ли это дополнительных «хлопот»?
@JackG не забывайте, что slice()
будет выделять новый массив, и действительно, splice()
также выделяет новый массив, поскольку он возвращает массив удаленных элементов (в данном случае пустой массив). Запуск теста для этих случаев показывает, что вставка выполняется быстрее (примерно на 30%), но мы находимся в диапазоне миллионов операций в секунду, поэтому, если ваше приложение не выполняет множество этих операций в тугая петля, это не будет иметь никакого значения.
@nickf Если вы объединяете небольшое количество элементов (особенно нулевых элементов), то небольшой массив, выделенный объединением, будет частью молодого поколения, которое представляет собой память с почти нулевой стоимостью. Для сравнения, создание копии большого массива будет использовать не новое пространство, а специальное пространство больших объектов, возможно, даже вызывая системный вызов для выделения большего объема памяти, если массив достаточно велик. Только в конкретном случае сращивания большая часть очень большого массива может сращиваться медленнее.
Для правильного функционального программирования и создания цепочек необходимо изобретение 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));
«абсолютно бессмысленный пустой массив» — он возвращает пустой массив только тогда, когда второй параметр равен 0. Если он больше 0, он возвращает элементы, удаленные из массива. Учитывая, что вы добавляете к прототипу, а splice
видоизменяет исходный массив, я не думаю, что «правильное функциональное программирование» находится где-то рядом с splice
.
Здесь мы говорим о вставке, и второй параметр Array.prototype.splice() должен быть равен нулю. И то, что он возвращает, не имеет никакого значения, кроме «я ничего не удалял», и поскольку мы используем его для вставки элемента, у нас уже есть эта информация. Если вы не хотите изменять исходный массив, вы можете сделать то же самое с двумя операциями Array.prototype.slice() и одной Array.prototype.concat(). Тебе решать.
Ваша вторая реализация является самой чистой из всей этой страницы, и у вас нет голосов. Пожалуйста, возьмите мою и продолжайте в том же духе. (вы должны просто избегать мутации прототипа, но вы уже это знаете)
Я думаю, стоит упомянуть, что оставшийся параметр - это новый ECMA 6th (developer.mozilla.org/en/docs/Web/JavaScript/Reference/…)
Несмотря на то, что на этот вопрос уже был дан ответ, я добавляю это примечание в качестве альтернативного подхода.
Я хотел поместить известное количество элементов в массив, в определенные позиции, поскольку они выходят из "ассоциативного массива" (т.е. объекта), который по определению не гарантируется отсортированный заказ. Я хотел, чтобы результирующий массив был массивом объектов, но объекты располагались в определенном порядке в массиве, поскольку массив гарантирует их порядок. Так что я сделал это.
Сначала исходный объект, строка 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);
insert
методы/* 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"]
/* 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"
Есть ли компактный способ, чтобы эта версия также объединила массив, когда он находит его в аргументах?
Я не понимаю первый результат ["b", "X", "Y", "Z", "c"]
. Почему не включен "d"
? Мне кажется, что если вторым параметром slice()
поставить 6 и в массиве 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
(с именем end
) — это отсчитываемый от нуля индекс, на котором следует закончить извлечение. slice
извлекает до, но не включает end
. Следовательно, после insert
у вас есть ["a", "b", "X", "Y", "Z", "c", "d"]
, из которого slice
извлекает элементы с индексами от 1
до 6
, т. Имеет ли это смысл?
По какой-то причине, когда я использую вставку2, я получаю исключение «Ожидается 1 аргумент, но получено 2».
Метод 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' ]
Чтобы вставить несколько элементов, вы можете использовать Array.prototype.insert = function (index, items) { this.splice.apply(this, [index, 0].concat(items)); }
.
Проблема с добавлением материала в массив заключается в том, что функция будет отображаться как элемент, когда вы делаете for(i in arr) {...}
Но имейте в виду, что не рекомендуется расширять собственные типы, поскольку это может помешать другому коду или будущим функциям.
Не изменяйте объекты, которыми вы не владеете
@RyanSmith Или, с ES6, Array.prototype.insert = function(index, ...items) { this.splice.call(this, index, 0, ...items); }
.
@SolomonUcko, да, вы могли бы использовать ES6, я бы просто сделал [...arr.slice(0, index), ...items, ...arr.slice(index)]
@RyanSmith Проблема в том, что нужно копировать начало массива, а не только конец.
@SolomonUcko, это правда, если вы работаете с большими массивами, это следует учитывать. Я думаю, что для небольших массивов преимущества неизменности перевешивают незначительные последствия для производительности. Обратите внимание, что здесь есть ответ, в котором используется этот подход coderhelper.com/a/38181008/1221906, поэтому, вероятно, лучше всего оставить отзыв для людей, которые используют этот подход.
Не изменяйте прототипы
Если вы хотите вставить несколько элементов в массив одновременно, ознакомьтесь с этим ответом 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);
Не лучше ли для функции insertAt() вызвать метод insertArrayAt() после того, как он создал одноэлементный массив arrayToInsert? Это позволяет избежать повторения идентичного кода.
это отличный пример того, когда использовать «применить»
Я добавил к этому методу параметр removeCount, чтобы воспользоваться преимуществами возможности splice также удалять элементы по этому индексу: Array.prototype.splice.apply(array, [index, removeCount || 0].concat(arrayToInsert));
Обратите внимание, что JQuery — это библиотека DOM и управления событиями, а не отдельный язык. Это не имеет ничего общего с манипуляциями с массивами.
api.jquery.com/jQuery.inArray не имеет ничего общего с DOM или событиями. jQuery превратился в смешанный набор инструментов для разработки JS в браузере, что привело к тому, что люди ожидают, что у него будет метод для всего.
@Tim, но это все еще не собственный язык (все еще есть некоторые вопросы, такие как «как суммировать два числа в jQuery» здесь, на SO)
@ Виктор Нет и никогда не будет. jQuery был полезен и актуален, но у него был свой день.
Кроме того, см. это, для извращенного сюрприза (:
Меня раздражает, что заголовок этого вопроса и заголовок его страницы отличаются (jQuery против JS). По-разному отображается в результатах поиска.