Javascript checking duplicate before insert into array - javascript

I was having some problem when trying to check for duplicate by multiple fields before inserting into the array. What I am trying to do is retrieve from firebase, check for accountID and subtype fields before inserting into the array to be resolved by Promise.
What I trying to achieve is If same accountID, different subtype, then I add; If same accountID, same subtype, I move to next; If different accountID, different subtype, I add. Here is my code:
code:
var datasetarr = [];
let promiseKey = new Promise((resolve, reject) => {
for(var i = 0; i < receiptlist.length; i++){
for(var k = 0; k < ritemlist.length; k++){
if(receiptlist[i].date.substring(0, 4) == new Date().getFullYear()){
if(ritemlist[k].receiptID == receiptlist[i].receiptID){
//check duplicate here before insert
if (!datasetarr.find(o => o.accountID === receiptlist[i].accountID && o.subtype === ritemlist[k].type))
datasetarr.push({accountID: receiptlist[i].accountID, subtype: ritemlist[k].type});
}
}
}
}
}
resolve(datasetarr);
});
The part when I tried to print out the array:
array:
promiseKey.then((arr) => {
console.log(arr);
});
The output I am getting:
output:
I still see a lot of duplicate with same accountID and same subtype. Is there anyway to resolve this?
Thanks!

find return undefined if there is no occurrence of your data; so what you have to do is to check whether the value returned is undefined and then you do your computation
var found = datasetarr.find(o => o.accountID === receiptlist[i].accountID && o.subtype === ritemlist[k].type)
if (found === undefined){
//do computation
}

You can use lodash which is very good library for array handling.
in your case data should be unique by accountId and your data is stored in data variable, you can use _.uniqBy() function like this:
jvar datasetarr = [];
let promiseKey = new Promise((resolve, reject) => {
for(var i = 0; i < receiptlist.length; i++){
for(var k = 0; k < ritemlist.length; k++){
if(receiptlist[i].date.substring(0, 4) == new
Date().getFullYear()){
if(ritemlist[k].receiptID == receiptlist[i].receiptID){
//Push your object here.
datasetarr.push({accountID: receiptlist[i].accountID, subtype: ritemlist[k].type});
}
}
}
}
}
//Before resolving check for the duplicates.
_.uniqBy(datasetarr, function (data) {
return data.accountID;
});
resolve(datasetarr);
});

let arr = ["Apple", "Orange"]
let newElement = "Apple"
if (!arr.includes(newElement)) arr.push(newElement)
else console.log("Element is already there")
console.log("Array Elements : " + arr)
Looking for other suitable methods for the same functionality.

Related

Create an array of search results

How can i get the name in the picture below?
return testData.then((data) => {
console.log(data)
var results = [];
var toSearch = params.suggestTerm;
data = data["data"]["0"];
console.log("data: ", data["0"])
for(var i=0; i<data.length; i++) {
if(data[i]["name"].indexOf(toSearch)!=-1) {
results.push(data[i]);
}
}
result of console.log(data)
No need to do this :data = data["data"]["0"];. If you are doing that you are assigning data to be the first object from the nested list. It is not an array anymore.
Just get the list in another variable and access that:
let list = data.data;
for(var i=0; i<list.length; i++) {
if(list[i]["name"].indexOf(toSearch) !== -1) {
results.push(list[i]);
}
}
The indexOf() search will be case sensitive. If that is not what you want, you can lowercase and search.
It appears you are looking to have an array only containing items that have name values in your toSearch string. If that's the case, you could use Array.filter() similar to:
return testData.then((data) => {
console.log(data)
var results = [];
var toSearch = params.suggestTerm;
if (data && data.data && data.data.length > 0){
results = data.data.filter(item =>
item.name.toLowerCase().indexOf(toSearch.toLowerCase()) > -1
)
return results;
}
This example searches case insensitive. If you wish for a case sensitive search, remove the .toLowerCase()
See Array.filter()

How do I manipulate a value of an array in javascript?

I'm quite new to Javascript and I have the following javascript array in an AJAX Request that contains the following:
["12435|#CANON#DEVICE#|#50#|Machine Detail|Details|SampleRow|FALSE|FALSE|FALSE|FALSE|FALSE|FALSE|TRUE"]
I wanna manipulate the TRUE and FALSE value. If they're in uppercase, I want to make it lowercase. Any idea how I can do it?
If you want to modify the list you could just loop through all of its items, modify the value and set it to the same index of the list. (You don't need to set it if you are dealing with objects).
var list = ["12435|#CANON#DEVICE#|#50#|Machine Detail|Details|SampleRow|FALSE|FALSE|FALSE|FALSE|FALSE|FALSE|TRUE"];
list.forEach(function(item, index) {
list[index] = item.replace(/(TRUE|FALSE)/g, function(upperCase) {
return upperCase.toLowerCase();
});
});
console.log(list);
Same thing using a for loop:
var list = ["12435|#CANON#DEVICE#|#50#|Machine Detail|Details|SampleRow|FALSE|FALSE|FALSE|FALSE|FALSE|FALSE|TRUE"];
for (var index = 0; index < list.length; index++) {
list[index] = list[index].replace(/(TRUE|FALSE)/g, function(upperCase) {
return upperCase.toLowerCase();
});
}
console.log(list);
If you want to create a copy you could do:
var list = ["12435|#CANON#DEVICE#|#50#|Machine Detail|Details|SampleRow|FALSE|FALSE|FALSE|FALSE|FALSE|FALSE|TRUE"];
var newList = list.map(function(item) {
return item.replace(/(TRUE|FALSE)/g, function(upperCase) {
return upperCase.toLowerCase();
});
});
console.log(newList);
The above scripts will also transform something like ["THIS IS NOT TRUE|TRUE|FALSE"] to ["THIS IS NOT true|true|false"]. If you do not want that you should use this regex instead /(^|(?<=\|))(TRUE|FALSE)(\||$)/ i.e.:
var list = ["12435|#CANON#DEVICE#|#50#|Machine Detail|Details|SampleRowFALSE|FALSE|FALSE|FALSE|FALSE|FALSE|FALSE|TRUE"];
for (var index = 0; index < list.length; index++) {
list[index] = list[index].replace(/(^|(?<=\|))(TRUE|FALSE)(\||$)/g, function(upperCase) {
return upperCase.toLowerCase();
});
}
console.log(list);
Just use replace with map:
const arr = ["12435|#CANON#DEVICE#|#50#|Machine Detail|Details|SampleRow|FALSE|FALSE|FALSE|FALSE|FALSE|FALSE|TRUE"];
const res = arr.map(e => e.replace(/(TRUE|FALSE)/g, m => m.toLowerCase()));
console.log(res);
const arrayString = ["12435|#CANON#DEVICE#|#50#|Machine Detail|Details|SampleRow|FALSE|FALSE|FALSE|FALSE|FALSE|FALSE|TRUE"]
const arrayOfValues = arrayString[0].split('|').map(val => {
if(val === 'TRUE' || val === 'FALSE') {
return val.toLowerCase();
} else {
return val;
}
});
console.log(arrayOfValues)
Use RegEx as you have been told before.
If you want to learn more about this look at: W3Schools
One solution could be like this:
var ajaxResponse = "12435|#CANON#DEVICE#|#50#|Machine Detail|Details|SampleRow|FALSE|FALSE|FALSE|FALSE|FALSE|FALSE|TRUE";
ajaxResponse = ajaxResponse.replace(/FALSE/g, "false");
ajaxResponse = ajaxResponse.replace(/TRUE/g, "true");
console.log(ajaxResponse);

iterate through nested array to match IDs

I have a set of data which is nested arrays, these arrays may be empty or they may infact contain an ID, if one of the arrays ID's matches the ID im comparing it with, I want to take all of the data inside that array which matched and assign it to a variable to be used...
example:
data = [[],[],[],[],[],[],[],[],[{"id":"123","name":"DARES HOUSE 2019","startDate":null,"endDate":null,"country":null,"city":null,"type":"Event","members":null}],[],[],[],[],[],[],[],[],[],[],[]]
id = 123
matchedArray =
for (var i = 0; i < potentialEvents.length; i++) {
for (var j = 0; j < potentialEvents[i].length; j++) {
if (id === potentialEvents[i].id) {
return;
}
}
}
console.log(matchedArray)
I'm trying to have it so matchedArray will be the array with thhe matched IDs!!
if you can help, thank you a lot!
You can do this with a combination of .map, .filter and .flat
var data = [[],[],[],[],[],[],[],[],[{"id":"123","name":"DARES HOUSE 2019","startDate":null,"endDate":null,"country":null,"city":null,"type":"Event","members":null}],[],[],[],[],[],[],[],[],[],[],[]]
var id = 123;
var matchedArray = data.map( arr => {
return arr.filter(x => x.id == id);
}).flat();
console.log(matchedArray);
You can use Array#filter method to filter the inner array and Array#flatMap method to concatenate filtered array into one.
let data = [[],[],[],[],[],[],[],[],[{"id":"123","name":"DARES HOUSE 2019","startDate":null,"endDate":null,"country":null,"city":null,"type":"Event","members":null}],[],[],[],[],[],[],[],[],[],[],[]];
let id = 123;
let matchedArray = data.flatMap(arr => arr.filter(obj => obj.id == id))
console.log(matchedArray)
I'd recommend to use .some rather then .filter/.map/.flatMap. The main benefit is that it allows to stop traversing array when element is found.
On big arrays with a lot of data it will be more efficient (≈50 times faster): jsperf test
const data = [[],[],[],[],[],[],[],[],[{"id":"123","name":"DARES HOUSE 2019","startDate":null,"endDate":null,"country":null,"city":null,"type":"Event","members":null}],[],[],[],[],[],[],[],[],[],[],[]]
const id = 123;
let matchedArray = null;
data.some((a) => {
return a.some((v) => {
if (v != null && v.id == id) {
matchedArray = a;
return true;
}
});
});
console.log(matchedArray);

push only unique elements in an array

I have array object(x) that stores json (key,value) objects. I need to make sure that x only takes json object with unique key. Below, example 'id' is the key, so i don't want to store other json objects with 'item1' key.
x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}]
var clickId = // could be "item1", "item2"....
var found = $.inArray(clickId, x); //
if(found >=0)
{
x.splice(found,1);
}
else{
x.push(new Item(clickId, obj)); //push json object
}
would this accomplish what you're looking for? https://jsfiddle.net/gukv9arj/3/
x = [
{"id":"item1","val":"Items"},
{"id":"item1","val":"Items"},
{"id":"item2","val":"Items"}
];
var clickId = [];
var list = JSON.parse(x);
$.each(list, function(index, value){
if(clickId.indexOf(value.id) === -1){
clickId.push(value.id);
}
});
You can't use inArray() because you are searching for an object.
I'd recommend rewriting a custom find using Array.some() as follows.
var x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}]
var clickId = "item1";
var found = x.some(function(value) {
return value.id === clickId;
});
alert(found);
Almost 6 years later i ended up in this question, but i needed to fill a bit more complex array, with objects. So i needed to add something like this.
var values = [
{value: "value1", selected: false},
{value: "value2", selected: false}
//there cannot be another object with value = "value1" within the collection.
]
So I was looking for the value data not to be repeated (in an object's array), rather than just the value in a string's array, as required in this question. This is not the first time i think in doing something like this in some JS code.
So i did the following:
let valueIndex = {};
let values = []
//I had the source data in some other and more complex array.
for (const index in assetsArray)
{
const element = assetsArray[index];
if (!valueIndex[element.value])
{
valueIndex[element.value] = true;
values.push({
value: element.value,
selected: false
});
}
}
I just use another object as an index, so the properties in an object will never be repated. This code is quite easy to read and surely is compatible with any browser. Maybe someone comes with something better. You are welcome to share!
Hopes this helps someone else.
JS objects are great tools to use for tracking unique items. If you start with an empty object, you can incrementally add keys/values. If the object already has a key for a given item, you can set it to some known value that is use used to indicate a non-unique item.
You could then loop over the object and push the unique items to an array.
var itemsObj = {};
var itemsList = [];
x = [{"id":"item1","val":"foo"},
{"id":"item2","val":"bar"},
{"id":"item1","val":"baz"},
{"id":"item1","val":"bez"}];
for (var i = 0; i < x.length; i++) {
var item = x[i];
if (itemsObj[item.id]) {
itemsObj[item.id] = "dupe";
}
else {
itemsObj[item.id] = item;
}
}
for (var myKey in itemsObj) {
if (itemsObj[myKey] !== "dupe") {
itemsList.push(itemsObj[myKey]);
}
}
console.log(itemsList);
See a working example here: https://jsbin.com/qucuso
If you want a list of items that contain only the first instance of an id, you can do this:
var itemsObj = {};
var itemsList = [];
x = [{"id":"item1","val":"foo"},
{"id":"item2","val":"bar"},
{"id":"item1","val":"baz"},
{"id":"item1","val":"bez"}];
for (var i = 0; i < x.length; i++) {
var item = x[i];
if (!itemsObj[item.id]) {
itemsObj[item.id] = item;
itemsList.push(item);
}
}
console.log(itemsList);
This is late but I did something like the following:
let MyArray = [];
MyArray._PushAndRejectDuplicate = function(el) {
if (this.indexOf(el) == -1) this.push(el)
else return;
}
MyArray._PushAndRejectDuplicate(1); // [1]
MyArray._PushAndRejectDuplicate(2); // [1,2]
MyArray._PushAndRejectDuplicate(1); // [1,2]
This is how I would do it in pure javascript.
var x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}];
function unique(arr, comparator) {
var uniqueArr = [];
for (var i in arr) {
var found = false;
for (var j in uniqueArr) {
if (comparator instanceof Function) {
if (comparator.call(null, arr[i], uniqueArr[j])) {
found = true;
break;
}
} else {
if (arr[i] == uniqueArr[j]) {
found = true;
break;
}
}
}
if (!found) {
uniqueArr.push(arr[i]);
}
}
return uniqueArr;
};
u = unique(x, function(a,b){ return a.id == b.id; });
console.log(u);
y = [ 1,1,2,3,4,5,5,6,1];
console.log(unique(y));
Create a very readable solution with lodash.
x = _.unionBy(x, [new Item(clickId, obj)], 'id');
let x = [{id:item1,data:value},{id:item2,data:value},{id:item3,data:value}]
let newEle = {id:newItem,data:value}
let prev = x.filter(ele=>{if(ele.id!=new.id)return ele);
newArr = [...prev,newEle]

Select array index by object value

If I have an array like this:
var array = [{ID:1,value:'test1'},
{ID:3,value:'test3'},
{ID:2,value:'test2'}]
I want to select an index by the ID.
i.e, I want to somehow select ID:3, and get {ID:3,value:'test3'}.
What is the fastest and most lightweight way to do this?
Use array.filter:
var results = array.filter(function(x) { return x.ID == 3 });
It returns an array, so to get the object itself, you'd need [0] (if you're sure the object exists):
var result = array.filter(function(x) { return x.ID == 3 })[0];
Or else some kind of helper function:
function getById(id) {
var results = array.filter(function(x) { return x.ID == id });
return (results.length > 0 ? results[0] : null);
}
var result = getById(3);
With lodash you can use find with pluck-style input:
_.find(result, {ID: 3})
Using filter is not the fastest way because filter will always iterate through the entire array even if element being search for is the first element. This can perform poorly on larger arrays.
If you are looking for fastest way, simply looping through until the element is found might be best option. Something like below.
var findElement = function (array, inputId) {
for (var i = array.length - 1; i >= 0; i--) {
if (array[i].ID === inputId) {
return array[i];
}
}
};
findElement(array, 3);
I would go for something like this:
function arrayObjectIndexOf(myArray, property, searchTerm) {
for (var i = 0, len = myArray.length; i < len; i++) {
if (myArray[i].property === searchTerm)
return myArray[i];
}
return -1;
}
In your case you should do:
arrayObjectIndexOf(array, id, 3);
var indexBy = function(array, property) {
var results = {};
(array||[]).forEach(function(object) {
results[object[property]] = object;
});
return results
};
which lets you var indexed = indexBy(array, "ID");

Categories