特定のインデックスで配列にアイテムを挿入する方法(JavaScript)?


2931

私は次のスタイルのJavaScript配列挿入メソッドを探しています:

arr.insert(index, item)

jQueryが望ましいですが、JavaScriptの実装はこの時点で行います。


96
JQueryはDOMおよびイベント操作ライブラリであり、独自の言語ではないことに注意してください。配列操作とは関係ありません。
ドミノ

25
api.jquery.com/jQuery.inArrayは、DOMやイベントとは何の関係もありません。jQueryは、ブラウザーJS開発用の混合ツールキットに進化し、あらゆるもののためのメソッドがあることを期待する人々につながりました。
Tim、

4
@Tim、しかしそれはまだそれ自身の言語ではありません(SOの「jQueryで2つの数値を合計する方法」のような質問がまだあります)
Victor

3
@Victorいいえ。jQueryは有用で関連性がありましたが、その日がありました。
ティム

1
また、ねじれた驚きについては、これを参照してください(:
noobie

回答:


4756

必要なのは、spliceネイティブ配列オブジェクトの関数です。

arr.splice(index, 0, item);指定されたインデックスに挿入itemarrます(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 2009

83
@ tags2k:関数はアイテムを挿入するだけではなく、その名前はすでにperlで確立されているためですか?
クリストフ


55
スプライス挿入できますが、挿入は頻繁ではありません。例: arr.splice(2,3)インデックス2で始まる3つの要素を削除します。3rd.... Nthパラメータを渡さないと、何も挿入されません。そのため、その名前insert()は正義にもなりません。
EBarr 2014年

14
「スプライス」という言葉は理にかなっていると思います。スプライスとは、参加または接続すること、また変更することを意味します。要素の追加または削除を伴う、現在「変更」している確立された配列があります。配列のどこから開始するか、次に削除する古い項目(ある場合)の数を指定し、最後にオプションで追加する新しい要素のリストを指定します。もちろん、スプライスはSFの素晴らしい用語でもあります。
Jakub Keller、

286

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)); }
Ryan Smith

7
配列にコンテンツを追加することの問題点は、(ARRにI)のために行うときに、関数は要素として表示されていることである{...}
rep_movsd

7
ただし、他のコードや将来の機能に干渉する可能性があるため、ネイティブ型を拡張することはお勧めしません。
marsze 2018

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"含まれていないのですか?の2番目のパラメータとして6をslice()指定し、指定されたインデックスから始まる配列に6つの要素がある場合、戻り値には6つの要素すべてが含まれるはずです。(DOCは言う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);=>[ ]
Alexis Wilke

@AlexisWilke最初の例では、コメントで参照しているsliceメソッドではなくを使用spliceしました。slice(名前付きend)の2番目のパラメーターは、抽出を終了するゼロベースのインデックスです。slice含まないものまで抽出しendます。したがって、後にinsertあなたが持っている["a", "b", "X", "Y", "Z", "c", "d"]、そこからsliceのインデックスを持つ要素を抽出し1、最大6のすなわち、"b""d"は含みません"d"。それは意味がありますか?
VisioN 2014

41

複数の要素を配列に一度に挿入する場合は、このスタックオーバーフローの回答を確認してください: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()は、単一要素のarrayToInsertを作成した後は、insertArrayAt()を呼び出した方がよいでしょうか?これにより、同じコードの繰り返しを回避できます。
Matt Sach、2012

1
これは、「適用」を使用する際の良い例です
CRice

このメソッドにremoveCountパラメータを追加して、そのインデックスでアイテムを削除するスプライスの機能を利用しました。
CRice

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
「完全に無意味な空の配列」-2番目のパラメータが0の場合にのみ空の配列を返します。0より大きい場合は、配列から削除された項目を返します。プロトタイプに追加していてsplice、元の配列を変更していることを考えると、「適切な関数型プログラミング」はの近くのどこにも属していないと思いますsplice
chrisbajorin

ここでは挿入について説明しており、Array.prototype.splice()の2番目のパラメーターはゼロでなければなりません。そして、それが返すものは、「私は何も削除していません」以外の意味がなく、アイテムを挿入するためにそれを使用しているので、すでにその情報を持っています。元の配列を変更したくない場合は、2つのArray.prototype.slice()オペレーションと1つのArray.prototype.concat()オペレーションを使用して同じことができます。それはあなた次第です。
Redu

1
2番目の実装はこのページ全体から最もクリーンであり、投票数はゼロです。私のものを持って、いい仕事を続けてください。(プロトタイプを変更することは避けるべきですが、すでに知っています)
NiKo

1
残りのパラメーターは新しいECMA 6番目(developer.mozilla.org/en/docs/Web/JavaScript/Reference/…)であることは言及する価値があると思います
Geza Turi

18

この場合は純粋なJavaScriptを使用することをお勧めします。JavaScriptには挿入メソッドもありませんが、組み込みのArrayメソッドであるスプライスと呼ばれる機能を備えたメソッドがあり ます。

splice()とは何かを見てみましょう...

splice()メソッドは、既存の要素を削除したり、新しい要素を追加したりして、配列の内容を変更します。

OK、以下の配列があるとします。

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

私たちが何をしたか見てみましょう...

もう一度スプライスを使用しますが、今回は2番目の引数として0を渡します。つまり、アイテムを削除しないことを意味しますが、同時に、3番目の引数である3を追加します。これは、2番目のインデックスに追加されます...

削除追加を同時に行うことができることに注意してください。たとえば、次のようにできます。

arr.splice(2, 2, 3);

インデックス2で2つのアイテムを削除し、インデックス2で3を追加すると、結果は次のようになります。

[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]は追加されないことに気づく価値があり、オーバーライドします。
sfratini、2018

乗っていない既存の配列に要素を追加します。例:let arrName = ['xxx'、 'yyy'、 'zzz']; arrName.splice(1、0、 'aaa'、 'bbb'、 'ccc'); 印刷後のarrName
Srikrushna

arrNameに4つ以上の要素がある場合、追加ではなく3番目を上書きします。それとも私はこれを間違った方法で見ていますか?
sfratini 2018

要素を中央に挿入すると、次の要素が上書きされずに移動します。問題、必要なものを明記してください。配列(例)と出力に必要なものを取得します。
plzが

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

2つの方法があります。

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

これはすでに回答されていますが、別のアプローチのためにこのメモを追加します。

既知の数の項目を配列、特定の位置に配置したかったのは、それらが「連想配列」(つまり、オブジェクト)から出てきたためです。これは、定義上、ソートされた順序であることが保証されていません。結果の配列はオブジェクトの配列にしたかったのですが、配列はオブジェクトの順序を保証するため、オブジェクトは配列内の特定の順序になっています。だから私はこれをやった。

まず、ソースオブジェクト、PostgreSQLから取得したJSONB文字列。各子オブジェクトの「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), []);
}

したがって、このようにして、インデックスに要素を挿入して新しい配列を返すことができます(クールな機能的な方法になります-プッシュやスプライスを使用するよりもはるかに優れています)。インデックスが配列の長さよりも大きい場合は、挿入されます最後に。


3

Array#splice()配列の変更を本当に避けたい場合を除いて、これが方法です。2つの配列を考えるarr1arr2、ここであなたがの内容を挿入する方法です、arr2arr1最初の要素の後に:

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

2

私はこれを試してみましたが、うまくいきます!

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

インデックスは、要素を挿入または削除する位置です。0、つまり2番目のパラメータは、削除するインデックスからの要素数を定義します。項目は、配列に作成する新しいエントリです。1つまたは複数にすることができます。

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

4
上記の答えをコピーして貼り付けてください。これは質問に値を追加するものではありません。新しい回答を追加するか、既存のものにコメントします。何か新しいことに貢献してみてください。私たちはこのコミュニティを台無しにしたくあり
ません

1

これは、私のアプリケーションの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には確かに少し混乱するインターフェースがあるため、上記のReduに同意する必要があります。そして、cdbajorinによって与えられた応答は、「2番目のパラメーターが0の場合にのみ空の配列を返します。0より大きい場合は、配列から削除された項目を返します」というのは正確ですが、要点です。関数の目的は、Jakob Kellerが先に述べたように、「結合または接続し、また変更することです。要素を追加または削除することを含む、現在変更中の確立された配列があります。」削除された要素の戻り値がある場合、それはせいぜいぎこちないです。そして、私はこの方法が、自然なように見えるもの、スプライスされた要素が追加された新しい配列を返した場合、連鎖にもっと適している可能性があることに100%同意します。次に、["19"、 "17"]。splice(1,0、 "18")。join( "...")など、返された配列で好きなことを行うことができます。それが削除されたものを返すという事実は、ちょっとナンセンスな私見です。メソッドの意図が「要素のセットを切り取る」ことであり、それが唯一の意図である場合は、おそらくそうです。でも、何を切り抜くのかわからないような気がするんですけど、そういう要素を切り捨てる理由はほとんどないですね。既存の配列を変更するのではなく、既存の配列から新しい配列が作成されるconcat、map、reduce、sliceなどのように動作するほうがよいでしょう。それらはすべて連鎖可能であり、それは重要な問題です。配列操作をチェーンすることはかなり一般的です。言語はどちらか一方の方向に進み、可能な限りそれに固執する必要があるようです。Javascriptは機能的で宣言的ではないため、標準からの奇妙な逸脱のように見えます。


-2

パフォーマンス

今日(2020.04.24)私は、大小のアレイ用に選択したソリューションのテストを実行します。私はChrome 81.0、Safari 13.1、Firefox 75.0のMacOs High Sierra 10.13.6でそれらをテストしました。

結論

すべてのブラウザ

  • 驚くべきことにslicereduce(D、E、F)に基づく小さなアレイの非インプレースソリューションでは、通常、インプレースソリューションよりも10倍から100倍高速です。
  • 大きな配列の場合、splice(AI、BI、CI)に基づくインプレースソリューションが最速でした(場合によっては、最大100倍ですが、配列のサイズによって異なります)。
  • 小規模なアレイの場合、BIソリューションは最も低速でした
  • 大きなアレイの場合、Eソリューションが最も遅くなりました

ここに画像の説明を入力してください

詳細

テストは、インプレースソリューション(AI、BI、CI)と非インプレースソリューション(D、E、F)の2つのグループに分けられ、2つのケースで実行されました。

  • 10個の要素を持つ配列のためのテスト-あなたはそれを実行することができますHERE
  • 1.000.000要素を持つ配列のためのテスト-あなたはそれを実行することができますHERE

テストされたコードは以下のスニペットに示されています

クロムの小さな配列の結果の例は以下のとおりです

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.