Related
I need to convert a nested array into 2D in javascript, somewhat similar to the question answered for python at link
How to convert 2d nested array into 2d array single?
For example, the array
[[[[[[[[
[16,12],[16,13],[16,14]]
],
[[[[[[
[46,42],[46,43]
]]]]],[
[62,58],[62,59],[62,60]
]]]]]],
[103,102]],[[118,114],[118,115],[118,116]]
]
needs to be converted to
[[16,12],[16,13],[16,14],[46,42],[46,43],[62,58],[62,59],[62,60],[103,102],[118,114],[118,115],[118,116]]
Please help, thanks in advance
This is what I tried, finally works after many trials :
function removeNestArray2D(object) {
var result = [];
if (Array.isArray(object)) { // check if object is valid array
for(var i=0; i<object.length; i++) {
if(!Array.isArray(object[i])) { // check is each of array element is a valid array
return object;
}
else {
var tmp = removeNestArray2D(object[i]);
if(tmp.length == 1) {
result = tmp[0];
}
else if (tmp.length == 2 && Number.isInteger(tmp[0]) && Number.isInteger(tmp[1])) {
result.push(tmp);
}
else {
for (var j=0; j<tmp.length; j++) {
result.push(tmp[j]);
}
}
}
}
}
return result;
}
Recursive approach will help here. Check each array item if there are size 2 and both are number values then push to result array otherwise continue iteration recursively.
const arr = [[[[[[[[
[16,12],[16,13],[16,14]]
],
[[[[[[
[46,42],[46,43]
]]]]],[
[62,58],[62,59],[62,60]
]]]]]],
[103,102]],[[118,114],[118,115],[118,116]]
];
const get2dArray = arr => {
const res = [];
const pushRecursive = arr => {
if (arr.length == 2 && arr.every(x => Number.isInteger(x))) {
res.push(arr);
} else {
arr.forEach(pushRecursive);
}
};
pushRecursive(arr);
return res;
};
console.log(get2dArray(arr));
function removeNestArray2D(object) {
var result = [];
if (Array.isArray(object)) { // check if object is valid array
for(var i=0; i<object.length; i++) {
if(!Array.isArray(object[i])) { // check is each of array element is a valid array
return object;
}
else {
var tmp = removeNestArray2D(object[i]);
if(tmp.length == 1) {
result = tmp[0];
}
else if (tmp.length == 2 && Number.isInteger(tmp[0]) && Number.isInteger(tmp[1])) {
result.push(tmp);
}
else {
for (var j=0; j<tmp.length; j++) {
result.push(tmp[j]);
}
}
}
}
}
return result;
}
I have 2 objects and i want to compare old with new and return the new one if values of object differs. I tryed multiple solutions and it seems i can't achieve this.
here is what i've tryed
var new_pkg ={scooter_id:"TM0060",lat:"45.747646",lng:"21.231496",alt:"99.200"};
var old_pkg={scooter_id:"TM0060",lat:"25.747746",lng:"31.221496",alt:"100.200"};
function difference(new_pkg, old_pkg) {
function changes(new_pkg, old_pkg) {
return _.transform(new_pkg, function(result, value, key) {
if (!_.isEqual(value, old_pkg[key])) {
result[key] = (_.isObject(value) && _.isObject(old_pkg[key])) ? changes(value, old_pkg[key]) : value;
}
});
}
return changes(new_pkg, old_pkg);
}
i want to return {lat:"45.747646",lng:"21.231496",alt:"99.200"};
You can compare object values by key and return difference object if there is difference:
var new_pkg ={scooter_id:"TM0060",lat:"45.747646",lng:"21.231496",alt:"99.200"};
var old_pkg={scooter_id:"TM0060",lat:"25.747746",lng:"31.221496",alt:"100.200"};
const getNew = (newObj, oldObj) => {
if (Object.keys(oldObj).length == 0
&& Object.keys(newObj).length > 0)
return newObj;
let diff = {};
for (const key in oldObj) {
if (newObj[key] && oldObj[key] != newObj[key] ) {
diff[key] = newObj[key];
}
}
if (Object.keys(diff).length > 0)
return diff;
return oldObj;
}
console.log(getNew(new_pkg, old_pkg));
Are they always objects with same properties? Like a model?
If so, then you can loop through one of them and compare values at given key.
var new_pkg ={scooter_id:"TM0060",lat:"45.747646",lng:"21.231496",alt:"99.200"};
var old_pkg={scooter_id:"TM0060",lat:"25.747746",lng:"31.221496",alt:"100.200"};
function getANewOneIfPropChanged(oldOne, newOne) {
for(prop in oldOne) {
if(oldOne[prop] !== newOne[prop]) {
return newOne;
}
}
return oldOne;
}
console.log(getANewOneIfPropChanged(old_pkg, new_pkg));
Actually though, according to your rules of taking a new object you can just always use a new one.
You take if a prop in new one is different than an old one, but if they are the same then it does not matter if you take a new one or an old one. (Unless references to the object itself are important)
Try this :
var new_pkg ={scooter_id:"TM0060",lat:"45.747646",lng:"21.231496",alt:"99.200"};
var old_pkg ={scooter_id:"TM0060",lat:"25.747746",lng:"31.221496",alt:"100.200"};
function compareObj(obj1, obj2) {
// Create arrays of property names
var obj1Props = Object.getOwnPropertyNames(obj1);
var obj2Props = Object.getOwnPropertyNames(obj2);
// If number of properties is different,
// objects are not equivalent
if (obj1Props.length != obj2Props.length) {
return false;
}
for (var i of obj1Props) {
if (obj1[i] !== obj2[i]) {
return false;
}
}
// If we made it this far, objects
// are considered equivalent
return true;
}
if (compareObj(old_pkg, new_pkg) === false) {
console.log(new_pkg);
}
I have the following function which takes some values that the user has entered and creates JavaScript objects from those values, then puts those objects in an array and returns the array:
function createObjects() {
var objectArray = [];
for (var i = 0; i < someCount; i++) {
var object = {
property1: someProperty1,
property2: someProperty2,
property3: someProperty3,
property4: someProperty4
};
objectArray.push(object);
}
return objectArray;
}
Now, I want to compare these objects' properties and determine whether any two contain all of the same values for property1, property2, property3, and property4. If any two of these objects have all four of the same values for these properties, I want a validation check to return false. Here is what I have so far:
function objectsAreUnique() {
var objects = createObjects();
for(var i = 0; i < objects.length; i++) {
//need to determine whether all four of the properties are the same for any two objects
//if(objectsAreSame) { return false; }
}
return true;
}
I have a few ideas, but I'm interested to see what is the most efficient way to achieve this. Thanks!
If you can guarantee that the properties will always be inserted in the same order (which will be the case if using an object literal as in your example), you can do this in ~O(n) using JSON.stringify and a Set:
function objectsAreUnique() {
const objects = createObjects();
return (new Set(objects.map(o => JSON.stringify(o)))).size == objects.length;
}
First, create a function to test whether two objects are the same. You can enter each property individually, or get creative with the JSON.stringify function
properties individually:
function objectsIdentical(obj1, obj2) {
return obj1.property1 == obj2.property1 && obj1.property2 == obj2.property2 && obj1.property3 == obj2.property3 && obj1.property4 == obj2.property4;
}
JSON.stringify (recommended for objects with many properties)
function objectsIdentical(obj1, obj2) {
return JSON.stringify(obj1).replace(/^.|.$/g, "").split(",").sort().join(",") == JSON.stringify(obj2).replace(/^.|.$/g, "").split(",").sort().join(",");
}
Then, you can use a for loop to check if any of them are identical.
for (let i=0; i<objects.length-1; i++) {
for (let j=i+1; j<objects.length; j++) {
if (objectsIdentical(objects[i], objects[j])) {
return false;
}
}
}
return true;
If you're familiar with the "some" function, you can use that.
return !objects.some((v, i) => objects.slice(i+1).some(w => objectsIdentical(v, w)))
function objectsAreUnique() {
var objects = createObjects();
var stringifiedAndSorted = objects.map(obj => JSON.stringify(obj)).sort()
for(var i = 0; i < stringifiedAndSorted.length-1; i++) {
if(i === i+1)
return false;
}
return true;
}
Running a test on my code. It should return 0 if the property passed into the function does not exist. But its not returning anything. Did I make a typo?
var obj = {
key: [1, 2, 3]
};
function getAverageOfElementsAtProperty(obj, key) {
if (obj[key].length === 0 || Array.isArray(obj[key]) === false || obj.hasOwnProperty(key) === false) {
return 0;
}
var average = 0;
for (var i = 0; i < obj[key].length; i++) {
average += obj[key][i];
}
average /= obj[key].length;
return average;
}
console.log(getAverageOfElementsAtProperty(obj, 'notKey'));
If you don't pass an array to your function, it fails when it tries to get the length of the object that was passed, so that shouldn't be how you test initially. You just need to see if the property exists and that is done by simply attempting to access the property in an if condition.
Now, if you are going to add tests to see if the property does exist and that it is an array, then you have to add more tests to check the items in the array to see if they are numbers, otherwise trying to get a numerical average will fail.
Since there are really two things to do (check if the property is there and get math average), I would break this into two functions:
var obj1 = {
key: [1, 2, 3]
};
var obj2 = {
key: [1, "test", 3]
};
function getAverageOfElementsAtProperty(obj, key) {
if (obj[key] && Array.isArray(obj[key])) {
// Ok, we have the right property and there is an array there,
// now we have to test that each item in the array is a number
var numbers = obj[key].every(function (currentValue) {
return typeof currentValue === "number";
});
// Return the average if we have all numbers or 0 if not
return numbers ? getAverage(obj[key]) : 0;
} else {
return 0;
}
}
function getAverage(arr){
var average = 0;
// Array.forEach() is much simpler than counting loops
arr.forEach(function(item) {
average += item;
});
return average / arr.length;
}
console.log(getAverageOfElementsAtProperty(obj1, 'notkey')); // 0
console.log(getAverageOfElementsAtProperty(obj1, 'key')); // 2
console.log(getAverageOfElementsAtProperty(obj2, 'key')); // 0 - obj2 does not contain all numbers
Since obj['notKey'] does not exist, it does not return an array. Therefore you cannot do .length of undefined. I would change it to typeof to see if its defined or not.
var obj = {
key: [1, 2, 3]
};
function getAverageOfElementsAtProperty(obj, key) {
if (typeof obj[key] == 'undefined' || Array.isArray(obj[key]) === false || obj.hasOwnProperty(key) === false) {
return 0;
}
var average = 0;
for (var i = 0; i < obj[key].length; i++) {
average += obj[key][i];
}
average /= obj[key].length;
return average;
}
console.log(getAverageOfElementsAtProperty(obj, 'notKey'));
I am a javascript beginner. I need to merge two arrays which contains objects which in turn contain arrays.
I have two arrays
arr1[
{
description : "this is a object",
array : [a.x,"b"]
}
]
arr2[
{
array : [a.z,"b","c","d"]
}
]
I have used the following code to perform the merge
function arrayUnique(array) {
var a = array.concat();
for(var i=0; i<a.length; ++i) {
for(var j=i+1; j<a.length; ++j) {
if(a[i] === a[j])
a.splice(j--, 1);
}
}
return a;
}
function combine(obj1,obj2) {
var res = {};
for (var k1 in obj1) {
if (!obj1.hasOwnProperty(k1)) continue;
if (obj2.hasOwnProperty(k1)) { // collision
if (typeof(obj1[k1]) !== typeof(obj2[k1])) throw "type mismatch under key \""+k1+"\".";
if (Array.isArray(obj1[k1])) {
res[k1] = obj1[k1].concat(obj2[k1]);
} else if (typeof(obj1[k1]) === 'string' || obj1[k1] instanceof String) {
res[k1] = arrayUnique(obj1[k1].concat(obj2[k1]));
} else if (typeof(obj1[k1]) === 'object') {
res[k1] = combine(obj1[k1],obj2[k1]);
} else {
throw "unsupported collision type "+typeof(obj1[k1])+" under key \""+k1+"\".";
}
} else {
res[k1] = obj1[k1];
}
}
for (var k2 in obj2) {
if (!obj2.hasOwnProperty(k2)) continue;
if (obj1.hasOwnProperty(k2)) continue; // already handled it above
res[k2] = obj2[k2];
}
return res;
}
var res = combine(arr1,arr2);
This is the result i expect
res = { description : "this is a object", array : [a.x,a.z,"b","c","d"] }
But unfortunately this is the result i get
res = { description : "this is a object", array : [a.x,"b","c","d"]}
a.z is ommited.
When both objects have the same array field you concatenate them (concat append the two arrays one after another), here:
if (Array.isArray(obj1[k1])) {
res[k1] = obj1[k1].concat(obj2[k1]);
If instead of ["a","a","b","b","c","d"] you want to get ["a","b","c","d"] you need to perform the array merge manually.
Check this answer for multiple ways to merge arrays without duplicates.