I have an array with variables. I would like to push some x and y coordinates into the array, but when i try to push instead of changing the variable values the push creates new variables and assign the value to those.
So it looks like this
0: {id: "t523470", name: "tPm1", x: 0, y: 0, parent: null, …}
1: {id: "t523471", name: "tPm2", x: 0, y: 0, parent: null, …}
2: {y: 651, x: 446}
3: {y: 800.015625, x: 802.328125}
Instead of this
0: {id: "t523470", name: "tPm1", x: 446, y: 651, parent: null, …}
1: {id: "t523471", name: "tPm2", x: 802.328125, y: 800.015625, parent: null, …}
function getModulePosition(id) {
for (let i = 0; i < axisViewElements.modules.length; i++) {
let currentElement = axisViewElements.modules[i].id;
if (id === currentElement) {
continue;
}
let module = document.getElementById(currentElement);
let modulePos = { x: module.getBoundingClientRect().left, y: module.getBoundingClientRect().top }
console.log(modulePos);
axisViewElements.modules.push({
y: modulePos.y,
x: modulePos.x
});
}
}
Array push method always insert a new element into an array. As you need to update an existing element you can simply do this:
axisViewElements.modules[i].y = modulePos.y;
axisViewElements.modules[i].x = modulePos.x;
Array.prototype.push always creates a new index with your values. You cannot use .push() and expect to change previous values in the Array. For your purpose you have to loop through your array, find the indexes you want to change some values in them and then assign your new values to them.
You are pushing to array which always creates a new element.
I'm assuming that your elements are unique inside array with respect to their id attribute. So you have to find the element with the id and then update the x and y attributes.
Your code will be like this:
elementToUpdate = axisViewElements.modules.find(el => el.id === you_id)
elementToUpdate.x = modulePos.x
elementToUpdate.y = modulePos.y
Try it here https://runkit.com/embed/pd68veqr5ey7
let input = [
{id: "t523470", name: "tPm1", x: 0, y: 0, parent: null},
{id: "t523471", name: "tPm2", x: 0, y: 0, parent: null}
];
let newValue = [
{y: 651, x: 446},
{y: 800.015625, x: 802.328125}
];
input.forEach((item, index) => item = Object.assign( item , newValue[index]));
console.log(input);
Related
I have the following array structure:
const array = [array1, array2, array3];
Each one of the three arrays consists of objects of form:
array1 = [{x: 0, y: 1}, {x: 5, y: 9}, {x: 1, y: 8}, {x: 3, y: 2}, etc]
I am trying to find the most efficient way to go through arrays of array and return the array to which a particular (unique) object belongs. For example I have object
{x:9, y:5}
which can be uniquely found in array2, so I want to return array2.
here's what I've tried:
const array = [array1, array2, array3];
for (let x = 0; x < array.length; x++) {
for (let y = 0; y < array[x].length; y++) {
array[x].find(e => e === array[x][y])
return array[x];
}
}
You'll need two loops, but you can use methods that do the iteration for you:
let array1 = [{x: 0, y: 1}, {x: 5, y: 9}, {x: 1, y: 8}, {x: 3, y: 2}];
let array2 = [{x: 5, y: 4}, {x: 4, y: 5}, {x: 8, y: 8}, {x: 3, y: 2}];
let array3 = [{x: 4, y: 3}, {x: 0, y: 6}, {x: 7, y: 8}, {x: 5, y: 2}];
const array = [array1, array2, array3];
let obj = array2[2]; // let's find this one...
let result = array.find(arr => arr.includes(obj));
console.log(result);
Here use find
data = [
[{x:1, y:2}, {x:2, y:3}],
[{x:3, y:2}, {x:4, y:3}],
[{x:5, y:2}, {x:6, y:3}],
[{x:7, y:2}, {x:8, y:3}]
];
const getArray = ({x, y}) => data.find(a => a.some(o => o.x === x && o.y === y));
console.log(getArray({x:3, y:2}));
TLDR; There is a working example in this fiddle
This can be accomplished using the following 3 things:
a library such as lodash to check for object equality (https://lodash.com/docs/4.17.15#isEqual)
The reason for this is that the behaviour of directly comparing two objects is different than you might think more info here
array.findIndex to find the index of the outer array (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex)
array.find to find the element in an inner array (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find)
The following method findObjectInNestedArray will do what you'd like.
const findObjectArray = (obj, arr) => {
index = arr.findIndex(a => a.find(e => _.isEqual(e, obj)))
return arr[index] // will return `undefined` if not found
}
// Example code below
const array1 = [{x: 0, y: 1}, {x: 5, y: 9}, {x: 1, y: 8}, {x: 3, y: 2}];
const array2 = [{x: 1, y: 1}, {x: 2, y: 2}, {x: 3, y: 3}, {x: 4, y: 4}, {x:9, y:5}];
const array3 = [{x: 5, y: 5}];
const arrays = [array1, array2, array3];
const inArray2 = {x:9, y:5};
const notInAnyArray = {x:0, y:0};
console.log('array2', findObjectArray(inArray2, arrays));
console.log('not in array', findObjectArray(notInAnyArray, arrays));
I know I said a single iteration was impossible before, but I devised a possible method that could work under specific circumstances. Essentially, you can sort the properties then stringify the objects for instant lookups. The sort is necessary to ensure you always get a consistent stringified output regardless of the object's properties preexisting order. There are three caveats to this method:
the objects CANNOT contain functions. Properties with functions are dropped in the stringification process.
NaN and infinity are converted to null, which can cause unexpected "matches" in the cache
If the depth of the object is not known (i.e. the target objects can contain references to arrays and other objects), then you'll need to deeply traverse through every level before stringifying.
It's a trade-off that's only improves performance when comparing deeply nested or extremely large objects. It's scalable, though, I guess.. Here's an example of how it could be done:
// sort's an array's values, handling subarrays and objects with recursion
const sortArr = arr => arr.sort().map(el => typeof el === 'object' ? (Array.isArray(el) ? sortArr(el) : sortObj(el)) : el)
// sorts a key's objects, then recreates the object in a consistent order
const sortObj = obj => Object.keys(obj).sort().reduce((final, prop) => {
final[prop] = (
// if it's an object, we'll need to sort that...
typeof obj[prop] === 'object'
? (
Array.isArray(obj[prop])
? sortArr(obj[prop])//<-- recursively sort subarray
: sortObj(obj[prop])//<-- recursively sort subobject
)
// otherwise, just retrun the value
: obj[prop]
)
return final
}, {})
// for every element in the given array, deeply sort then stringify it
const deepSortObjectArray = (arr) => arr.map(el => JSON.stringify(sortObj(el)))
// from those strings, create an object with the strings as values and an associated 'true' boolean
const obejctCache = (obj) => deepSortObjectArray(obj).reduce((acc, el) => ({[el]: true, ...acc}), {})
// create an object string cache for every object in the array:
const cacheObjectArrays = arr => arr.map(obj => obejctCache(obj))
// perform an O(1) lookup in each of the caches for a matching value:
const findArrayContainer = (obj, caches) => {
const stringLookupObj = JSON.stringify(sortObj(obj))
return caches.findIndex(cache => cache[stringLookupObj])
}
const array = [
{y: 1, x: 0},
{x: 5, y: 9},
{x: 1, y: 8},
{x: 3, y: {z: 3, x: 1, y: 2}}
]
const arrayArray = [[], [], array]
const cachesArrays = cacheObjectArrays(arrayArray)
console.log(cachesArrays)
/* output: [
{},
{},
{ '{"x":3,"y":{"x":1,"y":2,"z":3}}': true,'{"x":1, "y":8}': true, '{"x":5,"y":9}': true,'{"x":0,"y":1}': true }
]
*/
console.log(findArrayContainer({y: 1, x: 0}, cachesArrays))
// output: 2; working normally!
console.log(findArrayContainer({x: 0, y: 1}, cachesArrays))
// output: 2; working regardless of order!
console.log(findArrayContainer({y: 1, x: 0, q: 0}, cachesArrays))
// output: -1; working as expected with non-found objects!
As you can see, it's pretty complicated. Unless you're 100% this is actually the performance bottleneck, these performance gains may not translate to making interaction smoother.
Let me know if you have any questions about it!
I have a Array
var arr=[{t: "Lokanath", v: 0},
{t: "Das", v: 1}]
Is there any way that i can get the Record t: "Das", v: 1 based on the value of v i.e. v:1
Array.prototype.filter()
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
You can use filter() in the following way:
var a=[{text: "Lokanath", value: 0, id: 100},
{text: "Das", value: 1, id: 101}];
var das = a.filter(p => p.text=='Das');
console.log(das[0]);
Please Note: Since filter() returns an array, you have to use index to take the object.
var arr=[{text: "Lokanath", value: 0, id: 100},
{text: "Das", value: 1, id: 101}]
arr.find(d => d.text == "Das")
you can use filter method to do that.
var arr=[{text: "Lokanath", value: 0, id: 100},{text: "Das", value: 1, id: 101}];
console.log(arr.filter(o => o.text=='Das')[0]);
How to filter array by comparing two arrays of objects with different elements in their objects?
I have:
arr1 =[{ x: 1, y: 2, z:3 }, { x: 2, y: 1, z:4 }];
arr2 = [{ x: 1, y: 2, a:5 }, { x: 2, y: 3, a:4 }];
I want to compare x and y values from both arrays and return the not macthing object from first array, in the above example return [{ x: 2, y: 1, z:4 }]
I tried to use _.differenceWith(arr1, arr2, _.isEqual); but obviously for this the arrays should have similar objects which is not my case.
You are very close to the right answer.
The _.differenceWith function from lodash has three arguments, the array to inspect, the values to exclude and the third argument is a comparator which determines which values you need. In your case, using _.isEqual is looking for exactly the same object (which as far as I understood is not your desired behavior).
If you only care about having same x and y values, try using your custom comparator instead of the _.isEqual function from lodash.
It would look something like this:
const arr1 = [{ x: 1, y: 2, z:3 }, { x: 2, y: 1, z:4 }];
const arr2 = [{ x: 1, y: 2, a:5 }, { x: 2, y: 3, a:4 }];
// this is your custom comparator which is called with each value from the two arrays
// I gave descriptive names to the arguments so that it is more clear
const customComparator = (valueFromFirstArray, valueFromSecondArray) =>
valueFromFirstArray.x === valueFromSecondArray.x
&& valueFromFirstArray.y === valueFromSecondArray.y;
const result = _.differenceWith(arr1, arr2, customComparator);
console.log(result);
// will print [{x: 2, y: 1, z: 4}]
Or if you are not familiar with arrow functions, the custom comparator can be declared like this:
function customComparator(valueFromFirstArray, valueFromSecondArray) {
return valueFromFirstArray.x === valueFromSecondArray.x
&& valueFromFirstArray.y === valueFromSecondArray.y
}
Here is a fiddle where you can mingle around with the custom comparator if you'd like to.
Use the filter function
arr1 =[{ x: 1, y: 2, z:3 }, { x: 2, y: 1, z:4 }];
arr2 = [{ x: 1, y: 2, a:5 }, { x: 2, y: 3, a:4 }];
let notMatched = arr2.filter(function (item, index) {
return !(item.x === arr1[index].x && item.y == arr1[index].y);
});
console.log(notMatched);
I have an array of arrays like so.
data = [
[
{x: 1, y: 40},
{x: 2, y: 43},
{x: 3, y: 12},
{x: 4, y: 60},
{x: 5, y: 63},
{x: 6, y: 23}
], [
{x: 1, y: 12},
{x: 2, y: 5},
{x: 3, y: 23},
{x: 4, y: 18},
{x: 5, y: 73},
{x: 6, y: 27}
], [
{x: 1, y: 60},
{x: 2, y: 49},
{x: 3, y: 16},
{x: 4, y: 20},
{x: 5, y: 92},
{x: 6, y: 20}
]
];
I can find the maximum y value of data with a nested d3.max() call:
d3.max(data, function(d) {
return d3.max(d, function(d) {
return d.y;
});
});
I'm struggling to understand how this code actually works. I know the second argument of the d3.max() function specifies an accessor function - but I'm confused into how exactly calling d3.max() twice relates with the accessor function.
I guess what I'm asking for is a walkthrough of how javascript interprets this code. I've walked through it on the console but it didn't help unfortunately.
Sometimes it's all about the naming of the variables:
// the outer function iterates over the outer array
// which we can think of as an array of rows
d3.max(data, function(row) {
// while the inner function iterates over the inner
// array, which we can think of as an array containing
// the columns of a single row. Sometimes also called
// a (table) cell.
return d3.max(row, function(column) {
return column.y;
});
});
You can find the source code for the d3.max function here: https://github.com/d3/d3.github.com/blob/8f6ca19c42251ec27031376ba9168f23b9546de4/d3.v3.js#L69
Wow..! intriguing question really. Just for some sporting purposes here is an ES6 resolution of this problem by invention of an array method called Array.prototype.maxByKey() So here you can see how in fact it's implemented by pure JS.
Array.prototype.maxByKey = function(k) {
var m = this.reduce((m,o,i) => o[k] > m[1] ? [i,o[k]] : m ,[0,Number.MIN_VALUE]);
return this[m[0]];
};
var data = [
[{x: 1, y: 40},{x: 2, y: 43},{x: 3, y: 12},{x: 4, y: 60},{x: 5, y: 63},{x: 6, y: 23}],
[{x: 1, y: 12},{x: 2, y: 5},{x: 3, y: 23},{x: 4, y: 18},{x: 5, y: 73},{x: 6, y: 27}],
[{x: 1, y: 60},{x: 2, y: 49},{x: 3, y: 16},{x: 4, y: 20},{x: 5, y: 92},{x: 6, y: 20}]
],
maxObj = data.map(a => a.maxByKey("y")).maxByKey("y");
console.log(maxObj);
Here is the story of what's going on in this piece of code. We will find the index of the object by reducing. Our reduce method uses an initial value, which is array [0,Number.MIN_VALUE], which at index 0 has 0 and at index 1 position has the smallest possible number in JS. Initial values are set to the first argument. So here m starts with the initial value. Reduce will walk over the array items (objects in our case) one by one and each time o will be assigned to the current object and the last argument i is of course the index of the position we are currently working on. k is provided to our function as the key that we will be using to test the max value upon.
So there is this simple ternary comparison o[k] > m[1] ? [i,o[k]] : m which means check current object property given by k (o[k]) if it is less than m[1] (where m is [0,Number.MIN_VALUE] in the first turn) return m as [i,o[k]] (check how ternaries return result) if it is not less than m[1] then return m as it is. And at the end of the walk we will be reduced down to [index of the element with max k property value, the value of that k property] in that array.
So as you see it is very simple.
Is there a way to compare differences between arrays based on changes on their elements positions?
I have an original array of objects which undergoes a change on one of it's element's values, this change is mapped into a new array:
origElements = [{id: 1, value: 50},
{id: 2, value: 60},
{id: 3, value: 70}]
changedElements = [{id: 1, value: 50},
{id: 3, value: 60},
{id: 2, value: 120}]
var diff = _.difference(_.pluck(origElements, "id"), _.pluck(changedElements, "id"));
var result = _.filter(origElements, function(obj) { return diff.indexOf(obj.id) >= 0; });
In this case it is clear why 'result' would return nothing. As there's no difference of values between: [1, 2, 3] and [1, 3, 2]. What I'm trying to achieve here is a 'strict difference' which would look at index as well, thus returning some reference to the new order of the objects.
How about doing it this way:
var origElements = [{
id: 1,
value: 50
}, {
id: 2,
value: 60
}, {
id: 3,
value: 70
}];
var changedElements = [{
id: 1,
value: 50
}, {
id: 3,
value: 60
}, {
id: 2,
value: 120
}];
var origElementsIds = _.pluck(origElements, "id");
var changedElementsIds = _.pluck(changedElements, "id");
console.log("Are array element positions same ?",
origElementsIds.join() === changedElementsIds.join());