I have two arrays of objects
A = [{x: x1, y: y1 ...}, {x: x1, y: y1}];
and I am iterating over these upading
B.forEach((d, i) => d['x'] = A[i]['x']));
However, whenever I am now updating B, A is updating as well.
Edit: Apparently the problem is not above, so here is all I do:
I have 3 arrays of objects, A, B, C.
I initialize them as follows:
A = await d3.json(endpointA).then(res => res);
C = await d3.json(endpointB).then(res => res);
B = [...A];
They are the bound with .data(B) to some svg elements with d3 and updated.
I am guessing they get referenced but while I have now a few months behind me, this is still my first javascript project so I am not 100% sure.
Any suggestions are very welcome!
Thank you!
Your B only clones array itself, but you also need to clone the objects inside the array:
B = [...A].map(o => Object.assign({}, o));
As #Pointy pointed out, this will only work if objects don't have nested objects.
For nested objects you'd need a deep cloning function:
B = cloneObj(A);
function cloneObj(obj)
{
const ret = Array.isArray(obj) ? [] : {};
for(let o in obj)
{
if (obj[o] && typeof obj[o] == "object")
ret[o] = cloneObj(obj[o]);
else
ret[o] = obj[o];
}
return ret;
}
The basic issue is this:
B = [ ... A ];
That makes a shallow copy of A. Making deep copies of objects is, in the general case, pretty difficult because objects can have lots of "shapes". In your case, however, it's likely that the following trick will work:
B = A.map(v => JSON.parse(JSON.stringify(v)));
That uses the JSON facility to stringify each object in A, and then parse it back to an object. That trick does not always work; in particular, if an object has functions or various other data values that cannot be serialized to JSON, it will strip those values out of the objects.
I've two json objects. I have also used json.stringfy on them.
Json1 and json2 has certain keys.
Few keys are similar in both the objects while others are different.
I don't care if the values are different in both the objects.
I wanted to return the unmatched keys of Json1 along with its values after checking if the key exists in json2.
Ex:
Json1:{
"A":2,
"B": "jrrj" }
Json2 : {
"A" : 6,
"C" : "jrdj"
}
Output Expected:
Result: {
"B" : "jrrj"
}
I searched for the solution a lot on the SO but couldn't find a suitable one that does exactly the same and I'm unable to figure out one.
Please help me out.
P.S - right now I'm on js version ES5.
If that's flat object and keys that are missing from second object, you may:
Extract Object.keys() of the first object
Use Array.prototype.reduce() to traverse the latter and turn that into an object having its properties set to unique properties of the first object
Following is a quick demo:
const o1 ={"A":2,"B":"jrrj"},
o2 ={"A":6,"C":"jrdj"},
diff = Object
.keys(o1)
.reduce((r,key) =>
(!(key in o2) && (r[key] = o1[key]), r), {})
console.log(diff)
ES5-compatible version
const o1 ={"A":2,"B":"jrrj"},
o2 ={"A":6,"C":"jrdj"},
diff = Object
.keys(o1)
.reduce(function(r, key){
if(!(key in o2)) r[key] = o1[key]
return r
}, {})
console.log(diff)
const object_1 = {"A":2,"B":"jrrj"};
const object_2 = {"A":6,"C":"jrdj"};
var new_obj = {};
Object.keys(object_1).map(
function(obj_1_key){
if(!object_2[obj_1_key]){
new_obj[obj_1_key] = object_1[obj_1_key];
}
}
)
console.log(new_obj);
i have array of keys that i want to add as property with calculated val(not including on code) on empty object like this by reduce:
const f = ['a','b','c'].reduce((obj,key) => obj[key]='', {})
i was expecting the obj is the accumulator {} so i added properties that way? how do i make this work by reduce?
i was expecting and want it to result like this for that code:
{ a:'', b:'', c:'' }
but my code only results to empty string on console. how do i achieve it?
The value that the reduce callback returns will be the accumulator in the next iteration. So, in your code, obj only refers to the object in the first iteration - on the next iteration, it refers to what obj[key] = '' resolves to, which is the empty string.
Return the object instead:
const f = ['a', 'b', 'c'].reduce((obj, key) => {
obj[key] = '';
return obj;
}, {});
console.log(f);
You could use Object.fromEntries instead, if you wanted (though, it's very new, so for good cross-browser support, include a polyfill):
const f = Object.fromEntries(
['a', 'b', 'c'].map(key => [key, ''])
);
console.log(f);
Thanks for your time.
I have the following object in JavaScript:
{
"key1":"value1,value2,value3",
"key2":"value4,value5,value6"
}
Now I want to parse for a specific value and if the value exists, I want to return the key associated with it. Suppose that I am passing 'value3', it should return key1; if passing value5, it should return me key2 and so on.
What is the best way to implement it using Javascript, keeping in mind the execution time. I have tried using sting manipulation functions like indexOf, substr; but not most effective I believe.
TIA.
Here is a slightly different approach that will generate a map where the key is actually the value of your original values object.
The generated map will be a sort of fast lookup. Just to make things clear this solution is efficient as long as you need to do a lot of lookups. For a single, unique lookup this solution is the less efficient, since building the hashmap requires much more time than just looking up for a single value.
However, once the map is ready, acquiring values through keys will be incredibly fast so, if you need to later acquire multiple values, this solution will be more suitable for the use case.
This can be accomplished using Object.entries and Object.values. Further explanations are available in the code below.
The code below (despite not required) will also take care of avoiding indexOf with limit cases like searching 'value9' over 'value9999' which, on a regular string, would actually work with indexOf.
const values = {
"key1":"value1,value2,value3",
"key2":"value4,value5,value6",
"key3":"value444,value129839,value125390", // <-- additional test case.
"key4": "value9" // <-- additional test case.
};
const map = Object.entries(values).reduce((acc, [key, value]) => {
// If the value is invalid, return the accumulator.
if (!value) return acc;
// Otherwise, split by comma and update the accumulator, then return it.
return value.split(',').forEach(value => acc[value] = key), acc;
}, {});
// Once the map is ready, you can easily check if a value is somehow linked to a key:
console.log(map["value444"]); // <-- key 3
console.log(map["value9"]); // <-- key 4
console.log(map["Hello!"]); // undefined
To me, the fastest and most concise way of doing that would be the combination of Array.prototype.find() and String.prototype.includes() thrown against source object entries:
const src={"key1":"value1,value2,value3","key2":"value4,value5,value6"};
const getAkey = (obj, val) => (Object.entries(obj).find(entry => entry[1].split(',').includes(val)) || ['no match'])[0];
console.log(getAkey(src, 'value1'));
console.log(getAkey(src, 'value19'));
p.s. while filter(), or reduce(), or forEach() will run through the entire array, find() stops right at the moment it finds the match, so, if performance matters, I'd stick to the latter
Lodash has a function for this called findKey which takes the object and a function to determine truthiness:
obj = { 'key1': 'value1, value2, value3', 'key2': 'value4,value5,value6' }
_.findKey(obj, val => val.includes('value3'))
# 'key1'
_.findKey(obj, val => val.includes('value5'))
# 'key2'
Based on your search, you can use indexOf after looping through your object.
Here's an old school method:
var obj = {
"key1":"value1,value2,value3",
"key2":"value4,value5,value6"
}
function search (str) {
for (var key in obj) {
var values = obj[key].split(',');
if (values.indexOf(str) !== -1) return key
}
return null;
}
console.log(search('value1'))
console.log(search('value6'))
Or you can use Object.keys() with filter() method and get the index 0 of the returned array.
var obj = {
"key1":"value1,value2,value3",
"key2":"value4,value5,value6"
}
function search (str) {
return Object.keys(obj).filter((key) => {
const values = obj[key].split(',');
if (values.indexOf(str) !== -1) {
return key
}
})[0]
}
console.log(search('value1'))
console.log(search('value6'))
You can try iterating over each value in your object and then splitting the value on each comma, then checking if the value is in the returned array like so:
const myObj = {"key1":"value1,value2,value3","key2":"value4,value5,value6"}
function findKeyByValue(obj, value) {
for (var key in myObj) {
const valuesArray = myObj[key].split(',')
if (valuesArray.includes(value)) {
return key
}
}
}
const key = findKeyByValue(myObj, 'value5') // returns 'key2'
console.log(key)
EDIT: Changed loop for efficiency, and extracted code to function
This should do it. Just uses Object.entries and filters to find the entries that contain the value you're looking for. (Can find more than one object that has the desired value too)
var obj = {
"key1": "value1,value2,value3",
"key2": "value4,value5,value6"
};
var find = 'value2';
var key = Object.entries(obj).filter(([k, v]) => v.split(',').includes(find))[0][0];
console.log(key);
Might want to check the return value of Object.entries(obj).filter((o) => o[1].split(',').includes(find)) before trying to access it, in case it doesn't return anything. Like so:
var obj = {
"key1": "value1,value2,value3",
"key2": "value4,value5,value6"
};
function findKey(objectToSearch, valueToFind) {
var res = Object.entries(objectToSearch).filter(([key, value]) => value.split(',').includes(valueToFind));
if(res.length > 0 && res[0].length > 0) {
return res[0][0];
}
return false;
}
console.log(findKey(obj, 'value5'));
includes can be used to check whether a value is present in an array. Object.keys can be used for iteration and checking for the match.
function findKey(json, searchQuery) {
for (var key of Object.keys(json)) if (json[key].split(',').includes(searchQuery)) return key;
}
const json = {
"key1": "value1,value2,value3",
"key2": "value4,value5,value6"
}
console.log(findKey(json, 'value5'))
Use Object.entries with Array.prototype.filter to get what the desired key.
const data = {
"key1": "value1,value2,value3",
"key2": "value4,value5,value6"
};
const searchStr = 'value3';
const foundProp = Object.entries(data).filter(x => x[1].indexOf(searchStr) !== -1);
let foundKey = '';
if (foundProp && foundProp.length) {
foundKey = foundProp[0][0];
}
console.log(foundKey);
How to recognize array & object in js where typeof doesn’t come in handy?
var arr = [], ob = {};
As everything in js are objects,
if(typeof arr == typeof ob) => returns true
I want a operator or ... that will tell me that the variable is an array. I can then use only the arrayfunctions to objects which are array. How is that possible?
var arr = [], ob = {};
As everything in js are objects, even **Array is an Object but an instance of class Array
if(typeof arr == typeof ob) => returns true as Both are **Objects
So, how will you to identify objects.
This is where instanceof operator comes in handy, to identify whether its an array you can put a additional check cde:
if(arr instanceof Object && arr instanceof Array) => returns true
if(ob instanceof Object && ob instanceof Array) => returns false
You could use Array.isArray() method to check if a variable is array or otherwise.
var myArray = [1,2,3,4,5];
console.log(Array.isArray(myArray));
true
Among numerous simple/sophisticated comparisons, one difference is:
var arr = []; # arr.length => 0
var obj = {}; # obj.length => undefined
There are multiple ways of differentiating between array and object, some on them are already mentioned above i would like to just add on above answers.
First Approach
Differentiation using length, length property exist on Array but doesn't exist on Object
var arr = [1,2,3]; arr.length => 3
var obj = {name: 'name'}; obj.length => undefined
Note: This approach fails when someone declares object like below, we can use this approach only when we are sure we will not get any object having length property
var rectangle = {length: 50, width: 50}; rectangle.length => 50
Second Approach
Using instanceof Array
var arr = [1,2,3]; arr instanceof Array => true
var obj = {name: 'name'}; ojb instanceof Array => false
Third Approach
Using Array.isArray, this is most preferable approach and is supported by most of browser now
Note: Array.isArray is preferred over instanceof because it works
through iframes.
Array.isArray(arr) => true
true
Array.isArray(obj) => false
If you want to support i.e 8 browser the use Object.prototype.toString
We can write polyfill for i.e 8
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
Object.prototype.toString.call(arr); =>"[object Array]"
Object.prototype.toString.call(obj); =>"[object Object]"
Reference: isArray