Array.push()が存在しない場合は?


247

どちらの値も存在しない場合、どうすれば配列にプッシュできますか?これが私の配列です:

[
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" }
]

name: "tom"またはtext: "tasty"でアレイに再度プッシュしようとした場合、何も起こらないようにしたいのですが、どちらもない場合は、.push()

これどうやってするの?


5
配列の代わりに辞書(ハッシュ/ツリー)を使用します。
Thomas Eding、2010年

これらはすべてJavaScriptで利用できますか?
rahul



1
セットがオブジェクトの配列で機能しない
rffaguiar

回答:


114

カスタムメソッドでArrayプロトタイプを拡張できます。

// check if an element exists in array using a comparer function
// comparer : function(currentElement)
Array.prototype.inArray = function(comparer) { 
    for(var i=0; i < this.length; i++) { 
        if(comparer(this[i])) return true; 
    }
    return false; 
}; 

// adds an element to the array if it does not already exist using a comparer 
// function
Array.prototype.pushIfNotExist = function(element, comparer) { 
    if (!this.inArray(comparer)) {
        this.push(element);
    }
}; 

var array = [{ name: "tom", text: "tasty" }];
var element = { name: "tom", text: "tasty" };
array.pushIfNotExist(element, function(e) { 
    return e.name === element.name && e.text === element.text; 
});

5
私はあなたのキャンパー(コンパレータ?)が2つの引数を取るべきだと思います。これは、追加された値がインラインであり、関数でアクセスできる変数ではない場合を単純化します。array.pushIfNotExist({name: "tom"、text: "tasty"}、function(a、b){return a.name === b.name && a.text === b.text;});
Vincent Robert

26
なぜこれが言語にネイティブではないのか疑問に思っています-実装方法を忘れてください-「一意の場合にのみ追加する」という考えは非常に基本的であり、存在すると見なされます。
justSteve

9
inArrayではなくJavaScript 1.6メソッドIndexOfでArrayプロトタイプを拡張することをお勧めします。
Eugene Gluhotorenko 2013

7
Array.findIndex()あなたのコードが行うのと同じことを達成する組み込みのJS関数です。

4
組み込みオブジェクトを直接拡張することは悪い習慣です。
Slava Fomin II

429

文字列の配列(オブジェクトの配列ではない)の場合、呼び出しによって項目が存在するかどうかを確認できます。存在.indexOf()しない場合は、項目を配列にプッシュするだけです。

var newItem = "NEW_ITEM_TO_ARRAY";
var array = ["OLD_ITEM_1", "OLD_ITEM_2"];

array.indexOf(newItem) === -1 ? array.push(newItem) : console.log("This item already exists");

console.log(array)


50
これが正しいフラグが立てられていない理由がわかりません。これは外部を使用せず、拡張機能を作成する必要がなく、非常に単純です。opsの質問に対する完全な回答。
pimbrouwers 2016

39
最初の質問では、配列の値は文字列ではなくオブジェクトです(そして、値がオブジェクトの場合、このソリューションはそのままでは機能しません)。
Simon Hi

12
@EmilPedersen-そうではない。if (a.indexOf({ name: "tom", text: "tasty" })!=-1) a.push({ name: "tom", text: "tasty" })2回試してください。「類似した」オブジェクトを2回追加します。
commonpike

18
この回答は客観的に間違っているため削除する必要がありますが、それでも賛成票の最大数を集めました。
ニコラ

2
これは正解ではありません。なぜ受け入れられるのですか?配列内のオブジェクトではなく、Js配列に対してのみ機能します。
ディジタイ2017年

100

Array.findIndex関数を引数として取る関数を使用するのは非常に簡単です。

var a = [{name:"bull", text: "sour"},
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" }
]
var index = a.findIndex(x => x.name=="bob")
// here you can check specific property for an object whether it exist in your array or not

if (index === -1){
    a.push({your_object});
}
else console.log("object already exists")

8
これが正解です。
18年

2
存在しない場合、配列に要素を追加するのに最も関係があります
akshay bagade

1
ありがとう、どこでもこれを探していました。
dt192

41

http://api.jquery.com/jQuery.unique/

var cleanArray = $.unique(clutteredArray);

あなたもmakeArrayに興味があるかもしれません

前の例は、プッシュする前に存在するかどうかを確認すると言った場合に最適です。後から見ると、それをプロトタイプの一部として宣言できる(つまり、クラス拡張とも呼ばれます)と記載されているため、以下の大きな拡張はありません。

indexOfがinArrayより高速なルートかどうかわからないのですが?恐らく。

Array.prototype.pushUnique = function (item){
    if(this.indexOf(item) == -1) {
    //if(jQuery.inArray(item, this) == -1) {
        this.push(item);
        return true;
    }
    return false;
}

22
jQueryリンクから:Note that this only works on arrays of DOM elements, not strings or numbers.また、indexOfはIE8では機能しません:(
dmathisen

IE8で機能するlodash _.indexOfを使用できます
LTroya

25

これらの理由から、underscore.jsのようなjsライブラリを使用してください。使用:union:渡された配列の和集合を計算します。1つ以上の配列に存在する一意の項目のリストを順番に計算します。

_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]

8
これは新しい配列を返し、実際には既存の配列にプッシュしないことに注意してください。
ilovett 2014

4
私見では、非常に単純なものに対してテストするためのフレームワークを導入する必要は本当にありません
DrewT

24

このような?

var item = "Hello World";
var array = [];
if (array.indexOf(item) === -1) array.push(item);

オブジェクト付き

var item = {name: "tom", text: "tasty"}
var array = [{}]
if (!array.find(o => o.name === 'tom' && o.text === 'tasty'))
    array.push(item)

4
array.find配列全体を検索するため、これは悪い考えです。findIndex最初の出現までしか検索しないを使用します。

3
@ K48によると:stackoverflow.com/a/33759573/5227365「find」はアイテムを見つけた後に停止します
Pascal

19

これは非常に古い質問であることはわかっていますが、ES6を使用している場合は、非常に小さいバージョンを使用できます。

[1,2,3].filter(f => f !== 3).concat([3])

非常に簡単です。最初に、アイテムを削除するフィルターを追加します。既に存在する場合は、それを連結によって追加します。

より現実的な例を次に示します。

const myArray = ['hello', 'world']
const newArrayItem

myArray.filter(f => f !== newArrayItem).concat([newArrayItem])

配列にオブジェクトが含まれている場合、フィルター関数を次のように変更できます。

someArray.filter(f => f.some(s => s.id === myId)).concat([{ id: myId }])

3
ここではかなりエレガントなソリューションです。ありがとう!
ジョナサンピカソ

18

動的にプッシュ

var a = [
  {name:"bull", text: "sour"},
  {name: "tom", text: "tasty" },
  {name: "Jerry", text: "tasty" }
]

function addItem(item) {
  var index = a.findIndex(x => x.name == item.name)
  if (index === -1) {
    a.push(item);
  }else {
    console.log("object already exists")
  }
}

var item = {name:"bull", text: "sour"};
addItem(item);

簡単な方法で

var item = {name:"bull", text: "sour"};
a.findIndex(x => x.name == item.name) == -1 ? a.push(item) : console.log("object already exists")

配列にプリミティブ型/単純配列のみが含まれる場合

var b = [1, 7, 8, 4, 3];
var newItem = 6;
b.indexOf(newItem) === -1 && b.push(newItem);

2
手に健康を。シンプルで美しいソリューション@Gopala raja
naika

11

Setを使用することをお勧めします、

セットは一意のエントリのみを許可し、問題を自動的に解決します。

セットは次のように宣言できます:

const baz = new Set(["Foo","Bar"])

@Michaelに指摘していただきありがとうございます。最小限の労力で個別のデータを維持したい場合に適したソリューションです。FWIW、必要なときに要素をフェッチするために必要なCPUが少なくなるため、配列のパフォーマンスが向上することに注意することが重要です。
Ben

質問はについて尋ねるArray.pushのでSet.add、それと同等です。
bryc

9

簡単なコード、「indexOf」が「-1」を返す場合、要素が配列内にないことを意味し、条件「=== -1」がtrue / falseを取得します。

「&&」演算子は「and」を意味するため、最初の条件がtrueの場合、それを配列にプッシュします。

array.indexOf(newItem) === -1 && array.push(newItem);

@ D.Lawrenceはい。
Eric Valero

OPの質問を提供する他の受け入れられた回答があり、それらは少し前に投稿されました。回答投稿するときは、「良い回答を書くにはどうすればよいですか?」を参照してください。、特に古い質問に答える場合は、新しいソリューションまたは大幅に優れた説明を追加してください。
help-info.de

4

速度についてはわかりませんが、stringification+ indexOfは単純なアプローチです。配列を文字列に変換することから始めます。

let strMyArray = JSON.stringify(myArray);

次に、一連の属性と値のペアに使用できます。

if (strMyArray.indexOf('"name":"tom"') === -1 && strMyArray.indexOf('"text":"tasty"') === -1) {
   myArray.push({ name: "tom", text: "tasty" });
}

オブジェクト全体を検索する方が簡単です。

if (strMyArray.indexOf(JSON.stringify(objAddMe) === -1) { 
   myArray.push(objAddMe);
}

3

Arrayプロトタイプを拡張したくないシンプルなものが必要な場合:

// Example array
var array = [{id: 1}, {id: 2}, {id: 3}];

function pushIfNew(obj) {
  for (var i = 0; i < array.length; i++) {
    if (array[i].id === obj.id) { // modify whatever property you need
      return;
    }
  }
  array.push(obj);
}

3

誰もがそれほど複雑でない要件を持っている場合に備えて、ここに単純な文字列配列に対する答えの私の適応があります:

Array.prototype.pushIfNotExist = function(val) {
    if (typeof(val) == 'undefined' || val == '') { return; }
    val = $.trim(val);
    if ($.inArray(val, this) == -1) {
        this.push(val);
    }
};

更新:IE8との互換性のために、indexOfとtrimをjQueryの代替手段に置き換えました


それは素晴らしい解決策ですが、なぜトリムを使うのですか?
Dejan Dozet

2

オブジェクトの特定のプロパティで検索する場合は、マップとリデュースを使用しました。これは、直接オブジェクトの等価を実行すると失敗することが多いため便利です。

var newItem = {'unique_id': 123};
var searchList = [{'unique_id' : 123}, {'unique_id' : 456}];

hasDuplicate = searchList
   .map(function(e){return e.unique_id== newItem.unique_id})
   .reduce(function(pre, cur) {return pre || cur});

if (hasDuplicate) {
   searchList.push(newItem);
} else {
   console.log("Duplicate Item");
}

2

短い例:

if (typeof(arr[key]) === "undefined") {
  arr.push(key);
}

1
正しくありません。キーのプッシュには興味がなく、名前と値のペアをプッシュしたいのですが、それがまだ存在しない場合に限られます。
ステファン

2

aはあなたが持っているオブジェクトの配列です

a.findIndex(x => x.property=="WhateverPropertyYouWantToMatch") <0 ? 
a.push(objectYouWantToPush) : console.log("response if object exists");

1

コールバック関数とその「this」パラメーターを指定してfindIndexメソッドを使用できます。

注:古いブラウザはfindIndexを認識していませんが、ポリフィルを使用できます。

サンプルコード(元の質問では、新しいオブジェクトがプッシュされるのは、そのデータのいずれもが事前にプッシュされたオブジェクトにない場合に限られることに注意してください):

var a=[{name:"tom", text:"tasty"}], b;
var magic=function(e) {
    return ((e.name == this.name) || (e.text == this.text));
};

b={name:"tom", text:"tasty"};
if (a.findIndex(magic,b) == -1)
    a.push(b); // nothing done
b={name:"tom", text:"ugly"};
if (a.findIndex(magic,b) == -1)
    a.push(b); // nothing done
b={name:"bob", text:"tasty"};
if (a.findIndex(magic,b) == -1)
    a.push(b); // nothing done
b={name:"bob", text:"ugly"};
if (a.findIndex(magic,b) == -1)
    a.push(b); // b is pushed into a

1

私はここで答えるには遅すぎると思いますが、これは私が書いたメールマネージャーのためについに思いついたものです。私が必要とするすべての作品。

window.ListManager = [];
$('#add').click(function(){
//Your Functionality
  let data =Math.floor(Math.random() * 5) + 1 
  
  if (window.ListManager.includes(data)){
      console.log("data exists in list")
  }else{
       window.ListManager.push(data);
  }
  
  
  $('#result').text(window.ListManager);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>Unique List</h1>

<p id="result"></p>
<button id="add">Add to List</button>


0

これはオブジェクト比較のための機能です。場合によっては、比較するフィールドがたくさんあるかもしれません。単に配列をループし、既存のアイテムと新しいアイテムでこの関数を呼び出します。

 var objectsEqual = function (object1, object2) {
        if(!object1 || !object2)
            return false;
        var result = true;
        var arrayObj1 = _.keys(object1);
        var currentKey = "";
        for (var i = 0; i < arrayObj1.length; i++) {
            currentKey = arrayObj1[i];
            if (object1[currentKey] !== null && object2[currentKey] !== null)
                if (!_.has(object2, currentKey) ||
                    !_.isEqual(object1[currentKey].toUpperCase(), object2[currentKey].toUpperCase()))
                    return false;
        }
        return result;
    };

0

ここでは、2つの配列に対して1行でそれを行う方法があります。

const startArray = [1,2,3,4]
const newArray = [4,5,6]

const result = [...startArray, ...newArray.filter(a => !startArray.includes(a))]

console.log(result);
//Result: [1,2,3,4,5,6]

-1

結果がない場合は、jQuery grepを使用してプッシュできます。http//api.jquery.com/jQuery.grep/

これは基本的に「プロトタイプの拡張」ソリューションと同じソリューションですが、プロトタイプを拡張(または汚染)しません。


-2

foreachを使用して配列を確認し、存在する場合はアイテムをポップします。それ以外の場合は新しいアイテムを追加します...

サンプルnewItemValue&submitFieldsはキーと値のペアです

> //submitFields existing array
>      angular.forEach(submitFields, function(item) {
>                   index++; //newItemValue new key,value to check
>                     if (newItemValue == item.value) {
>                       submitFields.splice(index-1,1);
>                         
>                     } });

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