How can I push into an array if neither values exist? Here is my array:
[
{ name: "tom", text: "tasty" },
{ name: "tom", text: "tasty" },
{ name: "tom", text: "tasty" },
{ name: "tom", text: "tasty" },
{ name: "tom", text: "tasty" }
]
If I tried to push again into the array with either name: "tom"
or text: "tasty"
, I don't want anything to happen... but if neither of those are there then I want it to .push()
How can I do this?
This question is related to
javascript
arrays
json
push
not-exists
Use a js library like underscore.js for these reasons exactly. Use: union: Computes the union of the passed-in arrays: the list of unique items, in order, that are present in one or more of the arrays.
_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]
In case you need something simple without wanting to extend the Array prototype:
// 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);
}
Short example:
if (typeof(arr[key]) === "undefined") {
arr.push(key);
}
I used map and reduce to do this in the case where you wish to search by the a specific property of an object, useful as doing direct object equality will often fail.
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");
}
a is the array of objects you have
a.findIndex(x => x.property=="WhateverPropertyYouWantToMatch") <0 ?
a.push(objectYouWantToPush) : console.log("response if object exists");
Like this?
var item = "Hello World";
var array = [];
if (array.indexOf(item) === -1) array.push(item);
With object
var item = {name: "tom", text: "tasty"}
var array = [{}]
if (!array.find(o => o.name === 'tom' && o.text === 'tasty'))
array.push(item)
You can check the array using foreach and then pop the item if it exists otherwise add new item...
sample newItemValue &submitFields are key,value pairs
> //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});
In case anyone has less complicated requirements, here is my adaptation of the answer for a simple string array:
Array.prototype.pushIfNotExist = function(val) {
if (typeof(val) == 'undefined' || val == '') { return; }
val = $.trim(val);
if ($.inArray(val, this) == -1) {
this.push(val);
}
};
Update: Replaced indexOf and trim with jQuery alternatives for IE8 compatability
It is quite easy to do using the Array.findIndex
function, which takes a function as an argument:
var arrayObj = [{name:"bull", text: "sour"},
{ name: "tom", text: "tasty" },
{ name: "tom", text: "tasty" }
]
var index = arrayObj.findIndex(x => x.name=="bob");
// here you can check specific property for an object whether it exist in your array or not
index === -1 ? arrayObj.push({your_object}) : console.log("object already exists")
I know this is a very old question, but if you're using ES6 you can use a very small version:
[1,2,3].filter(f => f !== 3).concat([3])
Very easy, at first add a filter which removes the item - if it already exists, and then add it via a concat.
Here is a more realistic example:
const myArray = ['hello', 'world']
const newArrayItem
myArray.filter(f => f !== newArrayItem).concat([newArrayItem])
If you're array contains objects you could adapt the filter function like this:
someArray.filter(f => f.some(s => s.id === myId)).concat([{ id: myId }])
Push dynamically
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);
In simple method
var item = {name:"bull", text: "sour"};
a.findIndex(x => x.name == item.name) == -1 ? a.push(item) : console.log("object already exists")
If the array contains only primitive types/ simple array
var b = [1, 7, 8, 4, 3];
var newItem = 6;
b.indexOf(newItem) === -1 && b.push(newItem);
Here you have a way to do it in one line for two arrays:
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]
someArray = [{a: 'a1 value', b: {c: "c1 value"},
{a: 'a2 value', b: {c: "c2 value"}]
newObject = {a: 'a2 value', b: {c: "c2 value"}}
//New object which needs check for duplicity
let isExists = checkForExists(newObject) {
return someArray.some(function(el) {
return el.a === newObject.a && el.b.c === newObject.b.c;
});
}
// write your logic here
// if isExists is true then already object in an array else you can add
You can use jQuery grep and push if no results: http://api.jquery.com/jQuery.grep/
It's basically the same solution as in the "extending the prototype" solution, but without extending (or polluting) the prototype.
I guess i am too late to answer here however this is what i finally came up with for a mail manager i wrote. Works that's all i need.
window.ListManager = [];_x000D_
$('#add').click(function(){_x000D_
//Your Functionality_x000D_
let data =Math.floor(Math.random() * 5) + 1 _x000D_
_x000D_
if (window.ListManager.includes(data)){_x000D_
console.log("data exists in list")_x000D_
}else{_x000D_
window.ListManager.push(data);_x000D_
}_x000D_
_x000D_
_x000D_
$('#result').text(window.ListManager);_x000D_
});
_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>_x000D_
<h1>Unique List</h1>_x000D_
_x000D_
<p id="result"></p>_x000D_
<button id="add">Add to List</button>
_x000D_
My choice was to use .includes()
extending the Array.prototype as @Darrin Dimitrov suggested:
Array.prototype.pushIfNotIncluded = function (element) {
if (!this.includes(element)) {
array.push(element);
}
}
Just remembering that includes
comes from es6 and does not work on IE:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
You can use the findIndex method with a callback function and its "this" parameter.
Note: old browsers don't know findIndex but a polyfill is available.
Sample code (take care that in the original question, a new object is pushed only if neither of its data is in previoulsy pushed objects):
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
For an array of strings (but not an array of objects), you can check if an item exists by calling .indexOf()
and if it doesn't then just push the item into the array:
var newItem = "NEW_ITEM_TO_ARRAY";_x000D_
var array = ["OLD_ITEM_1", "OLD_ITEM_2"];_x000D_
_x000D_
array.indexOf(newItem) === -1 ? array.push(newItem) : console.log("This item already exists");_x000D_
_x000D_
console.log(array)
_x000D_
If you already have an array containing duplicates, transform the array of objects into an array of strings, and then use the Set()
function to eliminate duplicates:
// Declaring an array of objects containing duplicate objects
let arrayOfObjects = [{name: "tom", text: "tasty"}, {name: "tom", text: "tasty"}];
// Transforming array of objects into array of strings
let arrayOfStrings = arrayOfObjects.map(obj => JSON.stringify(obj));
// Creating a new set, Set() returns unique values by definition
let uniqueSet = new Set(arrayOfStrings);
// Transforming set into array and reversing strings to objects
let uniqueArrayOfObjects = [...uniqueSet].map(elem => JSON.parse(elem));
console.log(uniqueArrayOfObjects);
// [{name: "tom", text: "tasty"}]
If you don't have duplicates so far and you want to check for duplicates before pushing a new element:
// Declaring an array of objects without duplicates
let arrayOfObjects = [{name: "tom", text: "tasty"}];
// Transforming array of objects into array of strings
let arrayOfStrings = arrayOfObjects.map(obj => JSON.stringify(obj));
// Declaring new element as an example
let newElem = {name: "tom", text: "tasty"};
// Stringifying new element
let newElemString = JSON.stringify(newElem);
// At this point, check if the string is duplicated and add it to array
!arrayOfStrings.includes(newElemString) && arrayOfObjects.push(newElem);
console.log(arrayOfObjects);
// [{name: "tom", text: "tasty"}]
This is working func for an objects comparison. In some cases you might have lot of fields to compare. Simply loop the array and call this function with a existing items and new item.
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;
};
Not sure about speed, but stringification
+ indexOf
is a simple approach. Start with turning your array into a string:
let strMyArray = JSON.stringify(myArray);
Then for a series of attribute-value pairs you can use:
if (strMyArray.indexOf('"name":"tom"') === -1 && strMyArray.indexOf('"text":"tasty"') === -1) {
myArray.push({ name: "tom", text: "tasty" });
}
Finding a whole object is simpler:
if (strMyArray.indexOf(JSON.stringify(objAddMe) === -1) {
myArray.push(objAddMe);
}
I would suggest you use a Set,
Sets only allow unique entries, which automatically solves your problem.
Sets can be declared like so:
const baz = new Set(["Foo","Bar"])
Easy code, if 'indexOf' returns '-1' it means that element is not inside the array then the condition '=== -1' retrieve true/false.
The '&&' operator means 'and', so if the first condition is true we push it to the array.
array.indexOf(newItem) === -1 && array.push(newItem);
http://api.jquery.com/jQuery.unique/
var cleanArray = $.unique(clutteredArray);
you might be interested in makeArray too
The previous example is best in saying that check if it exists before pushing. I see in hindsight it also states you can declare it as part of the prototype (I guess that's aka Class Extension), so no big enhancement below.
Except I'm not sure if indexOf is a faster route then inArray? probably.
Array.prototype.pushUnique = function (item){
if(this.indexOf(item) == -1) {
//if(jQuery.inArray(item, this) == -1) {
this.push(item);
return true;
}
return false;
}
Source: Stackoverflow.com