Want to verify all list from referjson should be present in response json (response).
referjson = [
{
a: 1,
b: 2,
c: 4,
tag: "test"
},
{
a: 3,
b: 5,
tag: "mock"
},
...
];
response = [
{
tag: "mock",
a: 3,
b: 5,
c: 0,
d: 0,
e: 0
},
{
tag: "test",
a: 1,
b: 2,
c: 4,
d: 0,
e: 0
},
{
tag: "mocktest",
a: 3,
b: 5,
c: 0,
d: 0,
e: 0
},
...
];
Kindly help me to check one by one all the list ie { a: 1, b: 2, c: 4, tag: "test" } should be present in response then check for {a: 3, b: 5, tag: "mock" } and so on ..
function checkJSON(referjson, response) {
for (var i = 0; i < referjson.length; i++) {
if (response.contains(referjson[i])) {
print("**PASS");
}
else {
karate.log(x[i] + "-------------Fail");
}
}
}
My if doesn't do it for me.
I came with something like this...
const checkJson = (referjson, response) => {
//will have all the keys of obj so we can compare with response has all the keys too.
let keyValueIsEqual = [];
let flag;
let indexResponse = 0;
let indexReferjson = 0;
let numberOfEqualObj = 0;
while(indexResponse < response.length && indexReferjson < referjson.length){
const referjsonEntries = Object.entries(referjson[indexReferjson]);
const responseEntries = Object.entries(response[indexResponse]);
if(referjsonEntries.length === responseEntries.length) {
for (const [key, value] of referjsonEntries) {
flag = false;
for(const [keyRes, valueRes] of responseEntries) {
if(keyRes === key && value === valueRes) {
keyValueIsEqual.push(true);
flag = true;
}
}
if(!flag) {
indexResponse++;
keyValueIsEqual = [];
break;
}
if(keyValueIsEqual.length === referjsonEntries.length) {
//response has all the keys and values [key, value] in one object -> meaning that they have equal objects.
indexReferjson++;
indexResponse = 0;
keyValueIsEqual = [];
numberOfEqualObj++;
}
}
} else {
indexResponse++;
keyValueIsEqual = [];
}
}
if (numberOfEqualObj === referjson.length) {
//response have all objs that referjson contain
} else {
//response doesn't have all the objs that referjson contain
}
}
In your example, "referjson" and "response" are not actually jsons, they're an array of objects, so we can iterate over their's entries...
I check if "referjsonEntries.length" is equal to "responseEntries.length" because the object will only be equal if they have the same quantity of properties.
I created an array "keyValueisEqual" that will store "true" in case the object we're iterating over in "response" has the key and value equals to the object in "referjson". Created a flag that indicates that the object of "reponseEntries" has the key and value equals to the object of "referjsonEntries". So now we only need to check if "keyValueIsEqual" has same length of "referjsonEntries", wich means that response's object is equal to referjson's object, increase the number of "numberOfEqualObj" and in the end of the code I check if "numberOfEqualObj" has the same length of "referjson", wich means that "response" has at least all the objects that "referjson" has. Don't think it's the optimized solution, but it works.
Related
Suppose I have the following array of objects:
var list = [
{ a: 1,
b: { c: 'x', k: []}
},
{ a: 1,
b: {c: 'x', d: 8}
}
];
I want them to be merged into one "generic" object, for this example, it would be:
{a: 1, b: {c: 'x', d:'8', k[]}}
As you can see, all nested objects are merged too. But I can't gain it. If I use Object.assign it creates new nested objects if they are different, that is duplicates them:
var res = Object.assign({}, ...list);
// res: {
a: 1,
b: {c: 'x', k: []},
b: {c: 'x', d: 8}
}
You could try the following using the reduce method:
var list = [{
a: 1,
b: {
a: 4,
k: 3
}
}, {
a: 1,
s: 11,
b: {
ab: 4,
d: 8
}
}]
var result = list.reduce(function(acc, item) {
var obj = { ...item
}
Object.keys(obj).forEach(function(item) {
if (acc[item]) { //if a property with the the key, 'item' already exists, then append to that
Object.assign(acc[item], obj[item]);
} else { // else add the key-value pair to the accumulator object.
acc[item] = obj[item];
}
})
return acc;
}, {})
console.log(result);
Deep merging is not simple to do yourself, That blog uses deep merge.
If you don't have webpack or nodejs you can use deepmerge like so:
// see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25
var canUseSymbol = typeof Symbol === 'function' && Symbol.for
var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7
function isReactElement(value) {
return value.$$typeof === REACT_ELEMENT_TYPE
}
function isNonNullObject(value) {
return !!value && typeof value === 'object'
}
function isSpecial(value) {
var stringValue = Object.prototype.toString.call(value)
return stringValue === '[object RegExp]'
|| stringValue === '[object Date]'
|| isReactElement(value)
}
function defaultIsMergeableObject(value) {
return isNonNullObject(value)
&& !isSpecial(value)
}
function emptyTarget(val) {
return Array.isArray(val) ? [] : {}
}
function cloneUnlessOtherwiseSpecified(value, options) {
return (options.clone !== false && options.isMergeableObject(value))
? deepmerge(emptyTarget(value), value, options)
: value
}
function defaultArrayMerge(target, source, options) {
return target.concat(source).map(function(element) {
return cloneUnlessOtherwiseSpecified(element, options)
})
}
function mergeObject(target, source, options) {
var destination = {}
if (options.isMergeableObject(target)) {
Object.keys(target).forEach(function(key) {
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options)
})
}
Object.keys(source).forEach(function(key) {
if (!options.isMergeableObject(source[key]) || !target[key]) {
destination[key] = cloneUnlessOtherwiseSpecified(source[key], options)
} else {
destination[key] = deepmerge(target[key], source[key], options)
}
})
return destination
}
function deepmerge(target, source, options) {
options = options || {}
options.arrayMerge = options.arrayMerge || defaultArrayMerge
options.isMergeableObject = options.isMergeableObject || defaultIsMergeableObject
var sourceIsArray = Array.isArray(source)
var targetIsArray = Array.isArray(target)
var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray
if (!sourceAndTargetTypesMatch) {
return cloneUnlessOtherwiseSpecified(source, options)
} else if (sourceIsArray) {
return options.arrayMerge(target, source, options)
} else {
return mergeObject(target, source, options)
}
}
deepmerge.all = function deepmergeAll(array, options) {
if (!Array.isArray(array)) {
throw new Error('first argument should be an array')
}
return array.reduce(function(prev, next) {
return deepmerge(prev, next, options)
}, {})
}
var list = [{
a: 1,
b: {
c: 'x',
//merging 1,2 and 1,3 results in [1,2,1,3] you can change that in defaultArrayMerge
k: [1,2]
}
},
{
a: 1,
b: {
c: 'x',
k: [1,3],
d: 8
}
}];
console.log(
deepmerge.all(list)
)
You can use the reduce method. Remove the first element from the original list , that object will be the base method.
var list = [{
a: 1,
b: {
c: 'x',
k: []
}
},
{
a: 1,
b: {
c: 'x',
d: 8
}
}
];
// Remove the first element from the array. The first element will be
// the base object
// slice will return a new array without the first object
// apply reduce on this list
let _temp = list.slice(1);
let x = _temp.reduce(function(acc,curr,currIndex){
for(let keys in curr){
// checking if the base object have the same key as of current object
if(acc.hasOwnProperty(keys)){
// if base object and current object has the key then
// check if the type is an object
if(typeof curr[keys] ==='object'){
// now get the key from both the object
// & check which one is missong. Add that key and value to the
// base object
let keysFromACC = Object.keys(acc[keys]);
let keysFromCURR = Object.keys(curr[keys]);
keysFromCURR.forEach(function(item){
if(keysFromACC.indexOf(item) ===-1){
acc[keys][item] = curr[keys][item]
}
})
}
}
else{
// if the base object does not have key which current object
// has then add the key to base object
acc[keys]= curr[keys]
}
}
return acc;
},list[0]);
console.log(x)
function whatIsInAName(collection, source) {
var result = [];
var arr1 = Object.keys(source);
console.log(arr1);
for (var i = 0; i < collection.length; i++) {
for (var j = 0; j < arr1.length; j++) {
if (collection[i].hasOwnProperty(arr1[j]) === false) { //Check 1 if false go to next object in collection
break;
} else if (collection[i].hasOwnProperty(arr1[j])) {
console.log(source[arr1[j]], collection[i][arr1[j]])
if (source[arr1[j]] !== collection[i][arr1[j]]) { //Check 2 if value is not equal break loop and goto next object in collection
break;
}
continue; // if both check passes go for next property of source to check in object;
}
result.push(collection[i]); //if all values are present and checked in object push it in result array.
}
}
return result;
}
console.log(whatIsInAName(
[
{ a: 1, b: 2 },
{ a: 1 },
{ a: 1, b: 2, c: 2 }
], {
a: 1,
b: 2
}
));
I couldn't figure out the problem in my logic. I try to debug it even but can't find what the hell is a problem with logic.The program is to make a function that looks through an array of objects (first argument) and returns an array of all objects that have matching property and value pairs (second argument) Kindly help me over, please.
whatIsInAName([{ "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 2 }], { "a": 1, "b": 2 })
should return
[{ "a": 1, "b": 2 }, { "a": 1, "b": 2, "c": 2 }].
and
whatIsInAName([{ "a": 1 }, { "a": 1 }, { "a": 1, "b": 2 }], { "a": 1 })
should return
[{ "a": 1 }, { "a": 1 }, { "a": 1, "b": 2 }].
Well you are complicating it too much with these two for loops, you can do it better using Array built-in methods.
This is how you can do it using .filter() and .some() methods:
function whatIsInAName(collection, source) {
var result = [];
var arr1 = Object.keys(source);
console.log(arr1);
result = collection.filter(function(obj){
return !arr1.some(function(k){
return !obj[k] || obj[k] !== source[k];
});
});
return result;
}
console.log(whatIsInAName([{ a: 1, b: 2 }, { a: 1 }, { a: 1, b: 2, c: 2 }], { a: 1, b: 2 }));
Problem with your code :
What you are doing currently is that if all the if statements pass, and loops do not break anywhere, you put continue again at the last item of arr1. So, it goes to check next iteration, does not find it, and goes to next iteration in the collection loop. While doing this, it does not push any item to result.
Solution:
In your code: You should use continue like this.
if(j !==(arr1.length - 1))
continue;
This gives your code an opportunity to push item to result array.
Try this function
function whatIsInAName(arr, sources){
return arr.filter((item) => {
for(source in sources){
if(!item[source] || item[source] !== sources[source]){
return false;
}
}
return true;
})
}
I think you are over complicating things. A simple .filter() will do. Inside that .filter() you can check to see if every value for every key in source matches with the corresponding key in collection by using the handy, built-in .every() method.
function whatIsInAName(collection, source) {
var sourceKeys = Object.keys(source);
return collection.filter(function (coll) {
// if you want to return only exact matches, just add the test to make sure same # of keys, and all keys match w/ values.
// (Object.keys(coll).length === sourceKeys.length) && sourceKeys.every(...)
return sourceKeys.every(function (key) {
return coll[key] === source[key];
});
});
}
console.log(whatIsInAName(
[
{ a: 1, b: 2 },
{ a: 1 },
{ a: 1, b: 2, c: 2 }
], {
a: 1,
b: 2
}
));
Alternatively, with ES6 Syntax:
function whatIsInAName(collection, source) {
return collection.filter(coll => Object.keys(source).every(key => coll[key] === source[key]));
}
console.log(whatIsInAName(
[
{ a: 1, b: 2 },
{ a: 1 },
{ a: 1, b: 2, c: 2 }
], {
a: 1,
b: 2
}
));
Your issue is that you are hitting your continue instead of falling out of the loop. I updated your code here:
function whatIsInAName(collection, source) {
var result = [];
var arr1 = Object.keys(source);
console.log(arr1);
for (var i = 0; i < collection.length; i++) {
for (var j = 0; j < arr1.length; j++) {
if (!collection[i].hasOwnProperty(arr1[j])) { //Check 1 if false go to next object in collection
break;
} else if (collection[i].hasOwnProperty(arr1[j])) {
console.log(source[arr1[j]], collection[i][arr1[j]])
if (source[arr1[j]] !== collection[i][arr1[j]]) { //Check 2 if value is not equal break loop and goto next object in collection
break;
}else if(j < arr1.length - 1){
continue; // if both check passes go for next property of source to check in object;
}
}
result.push(collection[i]);
}
}
return result;
}
console.log(whatIsInAName(
[
{ a: 1, b: 2 },
{ a: 1 },
{ a: 1, b: 2, c: 2 }
],
{
a: 1,
b: 2
}
)); // result is [Object {...}, Object {...}] which objects are {a: 1, b: 2}, {a: 1, b: 2, c: 2}
This question already has answers here:
How can I access and process nested objects, arrays, or JSON?
(31 answers)
Closed 5 years ago.
I need to do a deep-iteration of a javascript object that can have nested objects and arrays and I need to execute a function on all of the numeric values and modify the object.
For example, lets say I need to multiply every number by 2.
const foo = (obj) => {
// multiply every numeric value by 2
};
const modified = foo({
a: 0,
b: 3,
c: {
d: 4,
e: {
f: 6,
g: [ 0, 3, 7, 3 ]
}
}
});
The value of modified should be:
{
a: 0,
b: 6,
c: {
d: 8,
e: {
f: 12,
g: [ 0, 6, 14, 6 ]
}
}
}
Since people typically want to know what you've tried, here's how far I got before being completely stumped.
const obj = {};
for(key in object) {
const item = object[key];
if(typeof item === 'object') {
// The levels deep is dynamic, so how would I keep doing this..
} else if(typeof item === 'array') {
obj[key] = item.map((a, b) => a * 2);
} else if(!isNaN(item)) {
obj[key] = item * 2;
}
}
Using recursion and expanding on your solution
function multiplyByTwo(objectToParse) {
const obj = {};
for (key in objectToParse) {
const item = object[key];
if (typeof item === 'object') {
obj[key] = multiplyByTwo(item);
} else if (typeof item === 'array') {
obj[key] = item.map((a, b) => a * 2);
} else if (!isNaN(item)) {
obj[key] = item * 2;
}
}
return obj;
}
const result = multiplyByTwo(object);
You probably want recursion in this case. This implementation works for any type of object and mapping function you give it, aka extremely generic
function mapper(obj, mappingFn, result) {
if (!result)
result = {};
Object.keys(obj)
.forEach(key => {
switch (typeof obj[key]) {
case 'string':
case 'number':
result[key] = mappingFn(obj[key]);
break;
// if obj[key] is an array, it still returns 'object', so we are good
case 'object':
mapper(obj[key], mappingFn, result);
break;
}
});
return result;
}
let data = {
a: 0,
b: 3,
c: {
d: 4,
e: {
f: 6,
g: [ 0, 3, 7, 3 ]
}
}
};
let result = mapper(data, value => value * 2);
console.log(result) // everything should be multiplied by 2
There's my solution.
const foo = (obj, operation) => {
let afterObj = obj;
for(item in afterObj) {
if(typeof afterObj[item] == "object") {
foo(afterObj[item], operation);
} else if (typeof afterObj[item] = "string") {
} else {
afterObj[item] = operation(afterObj[item]);
}
}
return afterObj;
};
const modified = foo({
a: 0,
b: 3,
c: {
d: 4,
e: {
f: 6,
g: [ 0, 3, 7, 3 ]
}
}
}, function(x) { return x*2 });
I am experimenting on objects, and what I am trying to achieve is to remove keys found in object1 if those keys exist in object2.
Here is the example:
var original = {
a: 1,
b: 2,
c: 3,
e: {
tester: 0,
combination: {
0: 1
}
},
0: {
test: "0",
2: "hello"
}
};
var badKeys = {
a: 1,
b: 2,
0: {
test: "0",
}
}
var expectedResult = {
c: 3,
e: {
tester: 0,
combination: {
0: 1
}
},
0: {
2: "hello"
}
}
I've tried using underscore difference function, but it doesn't work for objects, also not sure if this is the right function.
Can you help me to get the var expectedResult right?
You could use an iterative and recursive approach for geeting the wanted properties in a new object.
function deleteKeys(good, bad, result) {
Object.keys(good).forEach(function (key) {
if (bad[key] && typeof bad[key] === 'object') {
result[key] = {};
deleteKeys(good[key], bad[key], result[key]);
return;
}
if (!(key in bad) || good[key] !== bad[key]) {
result[key] = good[key];
}
});
}
var original = { a: 1, b: 2, c: 3, e: { tester: 0, combination: { 0: 1 } }, 0: { test: "0", 2: "hello", another: { a: { B: 2, C: { a: 3 } }, b: 2 } } },
badKeys = { a: 1, b: 2, 0: { test: "0", random: 2, another: { a: 1 } } },
result = {};
deleteKeys(original, badKeys, result);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This would be the algorithm:
function removeDifferences (original, removeKeys) {
// Get keys of to be deleted properties.
var keys = Object.keys(removeKeys);
// Iterate all properties on removeKeys.
for (key of keys) {
// Check if property exists on original.
if (typeof original[key] !== undefined) {
// If the property is an object, call same function to remove properties.
if (typeof removeKeys[key] === 'object') {
removeDifferences(original[key], removeKeys[key]);
} else {
delete original[key];
}
}
}
return original;
}
Applied to your case:
/* Your data. */
var original = {
a: 1,
b: 2,
c: 3,
e: {
tester: 0,
combination: {
0: 1
}
},
0: {
test: "0",
2: "hello"
}
};
var badKeys = {
a: 1,
b: 2,
0: {
test: "0",
}
};
var expectedResult = {
c: 3,
e: {
tester: 0,
combination: {
0: 1
}
},
0: {
2: "hello"
}
};
/* Function */
function removeDifferences(original, removeKeys) {
// Get keys of to be deleted properties.
var keys = Object.keys(removeKeys);
// Iterate all properties on removeKeys.
for (key of keys) {
// Check if property exists on original.
if (typeof original[key] !== undefined) {
// If the property is an object, call same function to remove properties.
if (typeof removeKeys[key] === 'object') {
removeDifferences(original[key], removeKeys[key]);
} else {
delete original[key];
}
}
}
return original;
}
/* Application */
var output = removeDifferences(original, badKeys);
console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can create recursive function that will return new object using for...in loop.
var original = {"0":{"2":"hello","test":"0"},"a":1,"b":2,"c":3,"e":{"tester":0,"combination":{"0":1}}}
var badKeys = {"0":{"test":"0"},"a":1,"b":2}
function remove(o1, o2) {
var result = {}
for (var i in o1) {
if (!o2[i]) result[i] = o1[i]
else if (o2[i]) {
if (typeof o1[i] == 'object' && typeof o2[i] == 'object') {
result[i] = Object.assign(result[i] || {}, remove(o1[i], o2[i]))
} else if (o1[i] != o2[i]) result[i] = o1[i]
}
}
return result
}
console.log(remove(original, badKeys))
Truly a job for some recursion and a bit of functional programming using a pure function. (Tested with Node v7.7.1)
"DoForAllNestedObjects" for applying some function "whattodo" on "every leaf on the dictionary tree" when there is an corresponding "leaf" in baddict.
let DoForAllNestedValues = (dict, baddict, whattodo) => {
for (let key in dict) {
if (typeof (dict[key]) === 'object' && typeof (baddict[key]) === 'object')
DoForAllNestedValues(dict[key], baddict[key], whattodo);
else
if (baddict[key])
whattodo(dict, key);
}
}
DoForAllNestedValues(original, badKeys, (obj, val) => delete obj[val]);
console.log(original);
i want to implement a function like this in js
function(arrayOfObjects, arrayOfValues, property) {
/*here i want to return all the objects of 'arrayOfObjects'
which satisfies the following condition
(index is the iterative index of array 'arrayOfObjects')
arrayOfObjects[index][property] is equivalent to any of
the values that lies in arrayOfValues */
};
example :
arrayOfObjects = [{ a: 1, b: 2 }, { a: 3, b:4 }, { a: 1, b :3 }];
arrayOfValues = [ 2, 3 ];
function(arrayOfObjects, arrayOfValues, 'b')
should return [{ a: 1, b: 2 }, { a: 1, b :3 }]
arrayOfObjects.filter(function (elem) {
return elem.hasOwnProperty(property)
&& -1 !== arrayOfValues.indexOf(elem[property]);
});
In case you need IE8 support: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#Compatibility
You can use the Array.prototype.filter functionality:
var a1 = [{ a: 1, b: 2 }, { a: 3, b:4 }, { a: 1, b :3 }];
var a2 = [2, 3];
var filtered = a1.filter(function(item) {
return a2.indexOf(item.b) != -1;
});
No, this is too complex problem to have some build-in operator or function in JS.
You must use some cycle to walk through the elements.
function(arrayOfObjects, arrayOfValues, property) {
var result = [];
for (var i = 0; i < arrayOfObjects; i++) {
for (var j = 0; j < arrayOfValues; j++) {
if (arrayOfObjects[i][property] === arrayOfValues[j]) {
result.push(arrayOfObjects[i]);
continue; //object already added, go to next one
}
}
}
return result;
};
function fun1(arrayOfObjects, arrayOfValues, property) {
var result = new Array();
for (var obj in arrayOfObjects){
if (arrayOfObjects[obj].hasOwnProperty(property) &&
arrayOfObjects[obj][property] == arrayOfValues[property]){
result.push(arrayOfObjects[obj]);
}
}
return result;
}
var arrayOfObjects = [{ a: 1, b: 2 }, { a: 3, b:4 }, { a: 1, b :3 }];
var arrayOfValues = new Array();
arrayOfValues['a'] = 2;
arrayOfValues['b'] = 3;
console.log(fun1(arrayOfObjects , arrayOfValues , 'b'));
Your arrayOfValues should be an 'associative array' or key-value-pair object which use key to match the property. This might more suit your logic.