I have an existing array of objects :
existingArray = [
{object1: 'object1'},
{object2: 'object2'}
{object3: 'object3'},
]
I receive a new one :
newArray = [
{object2: 'object2'},
{object3: 'object3'},
{object4: 'object4'}
]
I want only to modify the existing one to get the new one as the result (push+splice)
Here is what I have for now (is there a better way ?)
for (var i = 0; i < newArray.length; i++) {
// loop first to push new elements
var responseToTxt = JSON.stringify(newArray[i]);
var newStatement = false;
for(var j = 0; j < existingArray.length; j++){
var statementToTxt = JSON.stringify(existingArray[j]);
if(statementToTxt === responseToTxt && !newStatement){
newStatement = true;
}
}
if(!newStatement){
statements.push(response[i]);
}
}
var statementsToSplice = [];
for (var i = 0; i < existingArray.length; i++) {
// then loop a second time to split elements not anymore on the new array
var statementToTxt = JSON.stringify(existingArray[i]);
var elementPresent = false;
var element = false;
for(var j = 0; j < newArray.length; j++){
var responseToTxt = JSON.stringify(newArray[j]);
if(responseToTxt === statementToTxt && !elementPresent){
elementPresent = true;
} else {
element = i;
}
}
if(!elementPresent){
statementsToSplice.push(element);
}
}
Then I needed to split multiple times in the array :
existingArray = statementsToSplice.reduceRight(function (arr, it) {
arr.splice(it, 1);
return arr;
}, existingArray.sort(function (a, b) { return b - a }));
Here is the example :
https://jsfiddle.net/docmz22b/
So the final output should always be the new array, but only by push or splice the old one.
In this case, the final outpout will be
existingArray = [
{object2: 'object2'},
{object3: 'object3'}
{object4: 'object4'},
]
The new array could contains multiple new elements and/or deleted elements that is currently in the existingArray
Use shift() and push()
existingArray.shift(); //Removes the first element of the array
existingArray.push({'object4' : 'object4'});
Fiddle
I'm almost 100% sure that there is a better way to do it, but at least this works, feel free to comment any suggestions / optimizations.
existingArray = [
{object1: 'object1'},
{object2: 'object2'},
{object3: 'object3'}
];
newArray = [
{object2: 'object2'},
{object3: 'object3'},
{object4: 'object4'}
];
// Loop all the old values, if is not in the new array, remove it
existingArray.forEach(function(item) {
if(!inArray(item, newArray)) {
var idx = indexOfObjectInArray(item, existingArray);
existingArray.splice(idx, 1);
}
});
// Loop all the new values, if is not in the new array, push it
newArray.forEach(function(item) {
if (!inArray(item, existingArray)) {
existingArray.push(item);
}
});
// Auxiliar functions
function inArray(initialValue, array) {
testValue = JSON.stringify(initialValue);
return array.some(function(item) {
return testValue == JSON.stringify(item);
});
}
function indexOfObjectInArray(initialValue, array) {
var result = -1;
testValue = JSON.stringify(initialValue);
array.forEach(function(item, idx) {
if (testValue == JSON.stringify(item)) {
result = idx;
};
});
return result;
}
Maybe this helps. It features Array.prototype.forEach and Array.prototype.some.
Splice unwanted items
Look if object with same property exist
If yes, then assign new object
Else push the object
var existingArray = [
{ object1: 'object1' },
{ object2: 'object2' },
{ object3: 'object3' },
],
newArray = [
{ object2: 'object22' },
{ object3: 'object33' },
{ object4: 'object44' }
];
function update(base, change) {
var changeKeys = change.map(function (a) { return Object.keys(a)[0]; }),
i = 0;
while (i < base.length) {
if (!~changeKeys.indexOf(Object.keys(base[i])[0])) {
base.splice(i, 1);
continue;
}
i++;
}
change.forEach(function (a) {
var aKey = Object.keys(a)[0];
!base.some(function (b, i, bb) {
if (aKey === Object.keys(b)[0]) {
bb[i] = a; // if that does not work, use bb.splice(i, 1, a);
return true;
}
}) && base.push(a);
});
}
update(existingArray, newArray);
document.write('<pre>' + JSON.stringify(existingArray, 0, 4) + '</pre>');
Related
I have two arrays which I want to compare and check if there is an deleted item in one of these arrays. If there is show me the difference (deleted item)
Here is the code below how I would like to achieve this:
function compareFilters (a1, a2) {
var a = [], diff = [];
for (var i = 0; i < a1.length; i++) {
a[a1[i]] = true;
}
for (var i = 0; i < a2.length; i++) {
if (a[a2[i]]) {
delete a[a2[i]];
} else {
a[a2[i]] = true;
}
}
for (var k in a) {
console.log('k', k);
diff.push(k);
}
return diff;
}
console.log(filters);
console.log(filters, queryBuilderFilters, compareFilters(queryBuilderFilters, filters));
This will log both arrays which look like this:
[
0: {
id: "AggregatedFields.ReturnOnAdSpend",
label: "ROAS (Return on Ad Spend)",
type: "integer",
description: "The ROAS (Return on Ad Spend)."
},
1: {
id: "AggregatedFields.ROIExcludingAssisted",
label: "ROI excl. assisted",
type: "integer",
description: "The ROI excluding any assisted values.
}
]
And the output of the compareFilters function is 0: "[object Object]"
How can I return the label of the object in this function?
This example illustrates what you want
var completedList = [1,2,3,4,7,8];
var invalidList = new Set([3,4,5,6]);
// filter the items from the invalid list, out of the complete list
var validList = completedList.filter((item) => {
return !invalidList.has(item);
})
console.log(validList); // Print [1,2,7,8]
// get a Set of the distinct, valid items
var validItems = new Set(validList);
You can try this, supposing that the objects in each array have the same reference and are not copies:
function compareFilters (a1, a2) {
const a1l = a1.length;
const a2l = a2.length;
// Both arrays are considered to be equal
if(a1l === a2l) return;
let completed;
let unCompleted;
let deletedValue;
if(a1l > a2l) {
completed = a1;
unCompleted = a2;
} else {
completed = a2;
unCompleted = a1;
}
for(let i = 0; i < completed.lenth; i++) {
if(completed[i] !== unCompleted[i]) {
return completed[i].label;
}
}
}
It will return undefined in case both arrays has the same quantity of elements. Otherwise, it will return the label of first element that is in one array but not the another.
trialObject : {
'color': ['red','blue'],
'size': ['s','m'],
'material': ['cotton']
}
// RECURSION FUNCTION TO MAKE COMBINATIONS
makeObjectVariants(selected){
let key = Object.keys(selected)
if(Object.keys(selected).length === 1){
return selected[key[0]];
} else {
var result = [];
var currentArray = selected[key[0]]
delete selected[key[0]]
var restObjects = this.makeObjectVariants(selected) // call function again
for(var i = 0; i < restObjects.length; i++){
for (var j = 0; j < currentArray.length; j++) {
result.push([restObjects[i] +','+ currentArray[j]]);
}
}
return result; // resultant array
}
}
// OUTPUT
0:["cotton,s,red"]
1:["cotton,s,blue"]
2:["cotton,m,red"]
3:["cotton,m,blue"]
// EXPECTED OUTPUT
[{'material':cotton,'size':s,'color':red},...]
I want the output to contain key value pairs so that the array elements can be recognized which group they fall into.
I am facing problem in adding keys to the elements generated because m unable to keep track of the object keys
If you can use ES6 (default parameters, spread operator, arrow function, ...), the following code do the job:
var trialObject = {
color: ['red','blue'],
size: ['s','m'],
material: ['cotton']
};
var result = buildCombinations(trialObject);
console.log(result);
function buildCombinations(trialObject , keys = Object.keys(trialObject ), keyIndex = 0 , subObj = {}, res = []) {
trialObject[keys[keyIndex]].forEach(element => {
subObj[keys[keyIndex]] = element;
keys[keyIndex + 1] ? buildCombinations(trialObject , keys, keyIndex + 1, subObj, res) : res.push({...subObj});
});
return res;
}
Let's say we have the following js array
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
Is there a js builtin function or jQuery one with which you can search the array ar for val?
Thanks
***UPDATE*************
Taking fusion's response I created this prototype
Array.prototype.containsArray = function(val) {
var hash = {};
for(var i=0; i<this.length; i++) {
hash[this[i]] = i;
}
return hash.hasOwnProperty(val);
}
you could create a hash.
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var hash = {};
for(var i = 0 ; i < ar.length; i += 1) {
hash[ar[i]] = i;
}
var val = [434,677,9,23];
if(hash.hasOwnProperty(val)) {
document.write(hash[val]);
}
You can also use a trick with JSON serializing. It is short and simple, but kind of hacky.
It works, because "[0,1]" === "[0,1]".
Here is the working demo snippet:
Array.prototype.indexOfForArrays = function(search)
{
var searchJson = JSON.stringify(search); // "[3,566,23,79]"
var arrJson = this.map(JSON.stringify); // ["[2,6,89,45]", "[3,566,23,79]", "[434,677,9,23]"]
return arrJson.indexOf(searchJson);
};
var arr = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
document.body.innerText = arr.indexOfForArrays([3,566,23,79]);
function indexOfArray(val, array) {
var hash = {};
for (var i = 0; i < array.length; i++) {
hash[array[i]] = i;
}
return (hash.hasOwnProperty(val)) ? hash[val] : -1;
};
I consider this more useful for than containsArray(). It solves the same problem (using a hash table) but returns the index (rather than only boolean true/false).
Can you try this?
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
var sval = val.join("");
for(var i in ar)
{
var sar = ar[i].join("");
if (sar==sval)
{
alert("found!");
break;
}
}
Why don't you use javascript array functions?
function filterArrayByValues(array, values) {
return array.filter(function (arrayItem) {
return values.some(function (value) {
return value === arrayItem;
});
});
}
Or if your array is more complicated, and you want compare only one property but as result return whole object:
function filterArrayByValues(array, values, propertyName) {
return array.filter(function (arrayItem) {
return values.some(function (value) {
return value === arrayItem[propertyName];
});
});
}
More about used functions: filter() and some()
You can use Array.prototype.some(), Array.prototype.every() to check each element of each array.
var ar = [
[2, 6, 89, 45],
[3, 566, 23, 79],
[434, 677, 9, 23]
];
var val = [3, 566, 23, 79];
var bool = ar.some(function(arr) {
return arr.every(function(prop, index) {
return val[index] === prop
})
});
console.log(bool);
I guess there is no such JS functionality available. but you can create one
function arrEquals( one, two )
{
if( one.length != two.length )
{
return false;
}
for( i = 0; i < one.length; i++ )
{
if( one[i] != two[i] )
{
return false;
}
}
return true;
}
The problem with this is that of object/array equality in Javascript. Essentially, the problem is that two arrays are not equal, even if they have the same values. You need to loop through the array and compare the members to your search key (val), but you'll need a way of accurately comparing arrays.
The easiest way round this is to use a library that allows array/object comparison. underscore.js has a very attractive method to do this:
for (var i = 0; i < ar.length; i++) {
if (_.isEqual(ar[i], val)) {
// value is present
}
}
If you don't want to use another library (though I would urge you to -- or at least borrow the message from the Underscore source), you could do this with JSON.stringify...
var valJSON = JSON.stringify(val);
for (var i = 0; i < ar.length; i++) {
if (valJSON === JSON.stringify(ar[i]) {
// value is present
}
}
This will almost certainly be significantly slower, however.
You can use toString convertion to compare elements
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
s = !ar.every(a => (a.toString() != val.toString()));
console.log(s) // true
Use this instead
if (ar.join(".").indexOf(val) > -1) {
return true;
} else {
return false;
}
Use lodash isEqual
const isValIncludedInAr = ar.some(element => isEqual(element, val))
const arrayOne = [2,6,89,45];
const arrayTwo = [3,566,23,79];
const arrayThree = [434,677,9,23];
const data = new Set([arrayOne, arrayTwo, arrayThree]);
// Check array if exist
console.log( data.has(arrayTwo) ); // It will return true.
// If you want to make a set into array it's simple
const arrayData = [...data];
console.log(arrayData); // It will return [[2,6,89,45], [3,566,23,79], [434,677,9,23]]
needing some advice on how to do this properly recursively.
Basically what I'm doing, is entering in a bunch of text and it returns it as JSON.
For example:
The text:
q
b
name:rawr
Returns:
[
"q",
"b",
{
"name": "rawr"
}
]
And the following input:
q
b
name:rawr:awesome
Would return (output format is not important):
[
"q",
"b",
{
"name": {
"rawr": "awesome"
}
}
]
How can I modify the following code to allow a recursive way to have objects in objects.
var jsonify = function(input){
var listItems = input, myArray = [], end = [], i, item;
var items = listItems.split('\r\n');
// Loop through all the items
for(i = 0; i < items.length; i++){
item = items[i].split(':');
// If there is a value, then split it to create an object
if(item[1] !== undefined){
var obj = {};
obj[item[0]] = item[1];
end.push(obj);
}
else{
end.push(item[0]);
}
}
// return the results
return end;
};
I don't think recursion is the right approach here, a loop could do that as well:
var itemparts = items[i].split(':');
var value = itemparts.pop();
while (itemparts.length) {
var obj = {};
obj[itemparts.pop()] = value;
value = obj;
}
end.push(value);
Of course, as recursion and loops have equivalent might, you can do the same with a recursive function:
function recurse(parts) {
if (parts.length == 1)
return parts[0];
// else
var obj = {};
obj[parts.shift()] = recurse(parts);
return obj;
}
end.push(recurse(items[i].split(':')));
Here is a solution with recursion:
var data = [];
function createJSON(input) {
var rows = input.split("\n");
for(var i = 0; i < rows.length; i++) {
data.push(createObject(rows[i].split(":")));
}
}
function createObject(array) {
if(array.length === 1) {
return array[0];
} else {
var obj = {};
obj[array[0]] = createObject(array.splice(1));
return obj;
}
}
createJSON("p\nq\nname:rawr:awesome");
console.log(data);
Let's say we have the following js array
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
Is there a js builtin function or jQuery one with which you can search the array ar for val?
Thanks
***UPDATE*************
Taking fusion's response I created this prototype
Array.prototype.containsArray = function(val) {
var hash = {};
for(var i=0; i<this.length; i++) {
hash[this[i]] = i;
}
return hash.hasOwnProperty(val);
}
you could create a hash.
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var hash = {};
for(var i = 0 ; i < ar.length; i += 1) {
hash[ar[i]] = i;
}
var val = [434,677,9,23];
if(hash.hasOwnProperty(val)) {
document.write(hash[val]);
}
You can also use a trick with JSON serializing. It is short and simple, but kind of hacky.
It works, because "[0,1]" === "[0,1]".
Here is the working demo snippet:
Array.prototype.indexOfForArrays = function(search)
{
var searchJson = JSON.stringify(search); // "[3,566,23,79]"
var arrJson = this.map(JSON.stringify); // ["[2,6,89,45]", "[3,566,23,79]", "[434,677,9,23]"]
return arrJson.indexOf(searchJson);
};
var arr = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
document.body.innerText = arr.indexOfForArrays([3,566,23,79]);
function indexOfArray(val, array) {
var hash = {};
for (var i = 0; i < array.length; i++) {
hash[array[i]] = i;
}
return (hash.hasOwnProperty(val)) ? hash[val] : -1;
};
I consider this more useful for than containsArray(). It solves the same problem (using a hash table) but returns the index (rather than only boolean true/false).
Can you try this?
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
var sval = val.join("");
for(var i in ar)
{
var sar = ar[i].join("");
if (sar==sval)
{
alert("found!");
break;
}
}
Why don't you use javascript array functions?
function filterArrayByValues(array, values) {
return array.filter(function (arrayItem) {
return values.some(function (value) {
return value === arrayItem;
});
});
}
Or if your array is more complicated, and you want compare only one property but as result return whole object:
function filterArrayByValues(array, values, propertyName) {
return array.filter(function (arrayItem) {
return values.some(function (value) {
return value === arrayItem[propertyName];
});
});
}
More about used functions: filter() and some()
You can use Array.prototype.some(), Array.prototype.every() to check each element of each array.
var ar = [
[2, 6, 89, 45],
[3, 566, 23, 79],
[434, 677, 9, 23]
];
var val = [3, 566, 23, 79];
var bool = ar.some(function(arr) {
return arr.every(function(prop, index) {
return val[index] === prop
})
});
console.log(bool);
I guess there is no such JS functionality available. but you can create one
function arrEquals( one, two )
{
if( one.length != two.length )
{
return false;
}
for( i = 0; i < one.length; i++ )
{
if( one[i] != two[i] )
{
return false;
}
}
return true;
}
The problem with this is that of object/array equality in Javascript. Essentially, the problem is that two arrays are not equal, even if they have the same values. You need to loop through the array and compare the members to your search key (val), but you'll need a way of accurately comparing arrays.
The easiest way round this is to use a library that allows array/object comparison. underscore.js has a very attractive method to do this:
for (var i = 0; i < ar.length; i++) {
if (_.isEqual(ar[i], val)) {
// value is present
}
}
If you don't want to use another library (though I would urge you to -- or at least borrow the message from the Underscore source), you could do this with JSON.stringify...
var valJSON = JSON.stringify(val);
for (var i = 0; i < ar.length; i++) {
if (valJSON === JSON.stringify(ar[i]) {
// value is present
}
}
This will almost certainly be significantly slower, however.
You can use toString convertion to compare elements
var ar = [
[2,6,89,45],
[3,566,23,79],
[434,677,9,23]
];
var val = [3,566,23,79];
s = !ar.every(a => (a.toString() != val.toString()));
console.log(s) // true
Use this instead
if (ar.join(".").indexOf(val) > -1) {
return true;
} else {
return false;
}
Use lodash isEqual
const isValIncludedInAr = ar.some(element => isEqual(element, val))
const arrayOne = [2,6,89,45];
const arrayTwo = [3,566,23,79];
const arrayThree = [434,677,9,23];
const data = new Set([arrayOne, arrayTwo, arrayThree]);
// Check array if exist
console.log( data.has(arrayTwo) ); // It will return true.
// If you want to make a set into array it's simple
const arrayData = [...data];
console.log(arrayData); // It will return [[2,6,89,45], [3,566,23,79], [434,677,9,23]]