javascript find parent of array item - javascript

I have an array item like this:
var array = USA.NY[2];
// gives "Albany"
{"USA" : {
"NY" : ["New York City", "Long Island", "Albany"]
}}
I want to find the state from just having the array. How do I do this? Thanks.
function findParent(array) {
// do something
// return NY
}

In Javascript, array elements have no reference to the array(s) containing them.
To achieve this, you will have to have a reference to the 'root' array, which will depend on your data model.
Assuming USA is accessible, and contains only arrays, you could do this:
function findParent(item) {
var member, i, array;
for (member in USA) {
if (USA.hasOwnProperty(member) && typeof USA[member] === 'object' && USA[member] instanceof Array) {
array = USA[member];
for(i = 0; i < array.length; i += 1) {
if (array[i] === item) {
return array;
}
}
}
}
}
Note that I’ve renamed the array parameter to item since you’re passing along a value (and array item), and you expect the array to be returned.
If you want to know the name of the array, you should return member instead.

Here is a generic function that can be used to find the parent key of any kind of multi-dimentional object. I use underscore.js by habit and for conciseness to abstract array vs associative array loops.
(function (root, struct) {
var parent = null;
var check = function (root, struct) {
_.each(root, function (value, key) {
if (value == struct) {
parent = key;
} else if (root == struct) {
parent = '_root';
} else if (typeof value === 'object') {
check(value, struct);
}
});
}
check(root, struct);
return parent;
})

Related

I need to recursively check a dynamic Tree Structure in Javascript

I need your help. So the goal this time is that i want to recursively check my tree structure.
Basically this is what i need it to do:
On the on side i have a so called treeNode (example: 'Article.Artnr') and on the other a so called contextEntry (which has an 'Article').
I need to check if the name in treeNode exists in contextEntry, if it exists i need to check the type of it and than go on. Now the tricky Part: The next name in the namesSplit is 'Artnr' which i need to check if it is an property from 'Article' in the contextEntry. Again if it is i need to check it's type and go on. I don't know beforehand how deep my structure will be so i really would appreciate your help on this one.
let namesSplit = treeNode.name.split('.');
let key = namesSplit[0];
let contextEntry = exprData.contextEntry.find(_x => _x.name === key);
I have implemented my Recursive check like so:
function recursive(names, contextEntry) {
for (let i = 0; i < names.length; i++) {
if (names[i] === contextEntry.name) {
// getType(contextEntry.value);
console.log('Name found in Context: ' + names[i]);
continue;
}
if (names[i] == Object.keys(contextEntry.value)) {
console.log(getType(contextEntry.value));
console.log('Child Name found in Context: ' + names[i]);
// console.log(Object.values(contextEntry.value));
}
}
}
recursive(namesSplit, contextEntry);
I also have to check the type of every value from the Context.
There are 4 possible datatypes: Primitive, Array of Primitive,
Object, Array of Objects
if the value in the context is either Primitive or an Array of Primitives it will throw an error, if it is an Object i need to just extract the value of it and if it is an Array of Objects i need to find the right object and than extract the value from it
VariableType is an enum.
My Check Function is implemented like so:
function getType(contextEntry.value) {
if (Array.isArray(contextEntry.value)) {
for (let i of contextEntry.value) {
if (isPrimitive(i)) {
return VariableType.ARRAY_OF_PRIMITIVES;
}
}
if (contextEntry.value.some(val => typeof val === 'object')) {
return VariableType.ARRAY_OF_OBJECTS;
}
}
if (typeof contextEntry.value === 'object' && contextEntry.value !== null) {
return VariableType.OBJECT;
}
if (isPrimitive(contextEntry.value)) {
return VariableType.PRIMITIVE;
}
}

Sort Keys in Javascript Object

I have a Javascript Object that contains a mix of property types including simple strings, objects, arrays of objects... and so on.
I would like to sort the keys following this rule:
'Simple properties like strings or numbers appears always before more complex properties that contains arrays or objects'
I wrote the following function, that almost do what I am trying to achieve, but it converts the arrays into objects. This is not the desired behaviour. Can anybody help me to create a function that keep arrays as arrays and at the same time it sorts the objects inside arrays?
function sort(object){
if (typeof object != "object" )
return object;
var keys = Object.keys(object);
keys.sort(function(a,b){
if (typeof(object[a])!== 'object') { return -1 } else { return 1 }
});
Working jsfiddle:
http://jsfiddle.net/u01mn2py/3/
Kind Regards
As of ECMAScript 2015 (ES6), an object's own properties do have order for some operations, although relying on it is rarely a good idea. If you want order, usually it's best to use an array or similar.
The order is:
Let keys be a new empty List.
For each own property key P of O that is an integer index, in ascending numeric index order
Add P as the last element of keys.
For each own property key P of O that is a String but is not an integer index, in property creation order
Add P as the last element of keys.
For each own property key P of O that is a Symbol, in property creation order
Add P as the last element of keys.
Return keys.
That's for "own" properties. I don't think there are any externally-available operations that define a required order for all properties including inherited ones. (for-in is not required to follow the order above, not even in ES2015+.) As of ES2019, for-in does have a defined order (with some exceptions).
This means that it's probably possible to do what you asked, on a compliant engine, provided none of our keys qualifies as as an integer index.
JSON still has no order, but JSON.stringify is required by the JavaScript spec to use the order described above.
I'm not saying I suggest it. :-)
function sort(object) {
// Don't try to sort things that aren't objects
if (typeof object != "object") {
return object;
}
// Don't sort arrays, but do sort their contents
if (Array.isArray(object)) {
object.forEach(function(entry, index) {
object[index] = sort(entry);
});
return object;
}
// Sort the keys
var keys = Object.keys(object);
keys.sort(function (a, b) {
var atype = typeof object[a],
btype = typeof object[b],
rv;
if (atype !== btype && (atype === "object" || btype === "object")) {
// Non-objects before objects
rv = atype === 'object' ? 1 : -1;
} else {
// Alphabetical within categories
rv = a.localeCompare(b);
}
return rv;
});
// Create new object in the new order, sorting
// its subordinate properties as necessary
var newObject = {};
keys.forEach(function(key) {
newObject[key] = sort(object[key]);
});
return newObject;
}
Live Example (I also updated the fiddle):
function sort(object) {
// Don't try to sort things that aren't objects
if (typeof object != "object") {
return object;
}
// Don't sort arrays, but do sort their contents
if (Array.isArray(object)) {
object.forEach(function(entry, index) {
object[index] = sort(entry);
});
return object;
}
// Sort the keys
var keys = Object.keys(object);
keys.sort(function (a, b) {
var atype = typeof object[a],
btype = typeof object[b],
rv;
if (atype !== btype && (atype === "object" || btype === "object")) {
// Non-objects before objects
rv = atype === 'object' ? 1 : -1;
} else {
// Alphabetical within categories
rv = a.localeCompare(b);
}
return rv;
});
// Create new object in the new order, sorting
// its subordinate properties as necessary
var newObject = {};
keys.forEach(function(key) {
newObject[key] = sort(object[key]);
});
return newObject;
}
var object = {
family: [{
home: {
city: 'Madrid'
},
birth: {
city: 'Madrid'
},
name: 'John',
age: 32
}, {
home: {
city: 'London'
},
birth: {
city: 'Paris'
},
name: 'Marie',
age: 25
}],
name: 'Dani',
age: 33
};
var sortedObject = sort(object);
document.getElementById('container').innerHTML = JSON.stringify(sortedObject, null, '\t');
<pre id="container">
</pre>
(You didn't ask for alphabetical within categories, but it seemed a reasonable thing to throw in.)
That works for me on current Chrome, Firefox, and IE11.
I know I can't relay on javascript properties order, but I need visually to show sorted JSON. Solved in this way:
http://jsfiddle.net/u01mn2py/4/
function sort(object){
if (typeof object != "object" ) // Not to sort the array
return object;
var keys = Object.keys(object);
keys.sort(function(a,b){
if (typeof(object[a])!== 'object') { return -1 } else { return 1 }
});
if( Object.prototype.toString.call( object ) === '[object Array]' ) {
var newObject = [];
} else {
var newObject = {}; }
for (var i = 0; i < keys.length; i++){
newObject[keys[i]] = sort(object[keys[i]])
}
return newObject;
}

JSON get a value if another value

Okay so my JSON is something along the lines of:
{
"wares":[
{
"id":"1",
"name":"apples",
"stock":"40",
},
{
"id":"2",
"name":"pears",
"stock":"40",
},
{
"id":"3",
"name":"bananas",
"stock":"30",
}
]
}
So I would like to get the name if the stock is 40, I've used this code as an example, which I found here: http://techslides.com/how-to-parse-and-search-json-in-javascript/
function getObjects(obj, key, val) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getObjects(obj[i], key, val));
} else
//if key matches and value matches or if key matches and value is not passed (eliminating the case where key matches but passed value does not)
if (i == key && obj[i] == val || i == key && val == '') { //
objects.push(obj);
} else if (obj[i] == val && key == ''){
//only add if the object is not already in the array
if (objects.lastIndexOf(obj) == -1){
objects.push(obj);
}
}
}
return objects;
}
which works, but I haven't quite found a way to return the name if the stock is 40.
I was thinking you put an extra value in the function called ret (return) as in what it should return. Something along the lines of
alert(JSON.stringify(getObjects(JSON, 'stock', '40', 'name')));
Thanks a lot!
An alternate solution using the native filter() and map() methods:
function getObjects(_object, _key, _value, _return) {
return _object.filter(function(_item) {
return _item[_key] == _value;
}).map(function(_item) {
return _item[_return];
});
}
Note that in the above call, we need to pass the array containing the items, not the root object. Or you can modify the above to accept the root object
And you call it like:
getObjects(obj.wares, 'stock', 40, 'name');
to get back ["apples", "pears"]
Try this out!
$.each(getObjects(JSON, "stock", "40"), function() {
alert(this.name);
})
EDIT: Just in order to explain what I wrote, the getObjects function returns all the objects that matches the search criteria, so then what I did was to get each name of all the JSONS that are returned

Find an item not in array

I have an array of objects that can have up to 6 products in them e.g.
var products = [{name:'Trampoline'}, {name:'Net'}, {name:'Tent'}, {name:'Hoop'}];
// missing Ladder & Anchor
I need a way to check through them, and have it tell me that 'Ladder' and 'Anchor' aren't in the array products. !$.inArray doesn't work (the jquery one).
Can anyone help?? Maybe my brain has just died for the day, cos I just can't figure it out.
I tried starting with an array of all the items it needs, but the first loop through just removes them all becase the first one is not an accessory.
this.getUpsellItem = function() {
var p = this.getProduct();
var slots = ['Net','Tent','Ladder','Basketball','Anchor'];
for(var i = 0; i< p.length; i++) {
if(p[i].display_name2.indexOf('Net') === -1) slots.splice(0,1);
if(p[i].display_name2.indexOf('Tent') === -1) slots.splice(1,1);
if(p[i].display_name2.indexOf('Anchor') === -1) slots.splice(3,1);
if(p[i].display_name2.indexOf('Ladder') === -1) slots.splice(2,1);
if(p[i].display_name2.indexOf('Basketball') === -1) slots.splice(4,1);
console.log(p[i].display_name2.indexOf('Basketball'))
}
console.log('Printing slots')
print_r(slots)
};
Since you're using jQuery we can use the handy jQuery.grep() function to return only the elements in slots that aren't present in products. $.grep takes a function that it uses to filter which elements in the array it should return and which it should discard. In this case we just test each item in slots using products.indexOf. Something like this should suffice:
var slots = [ 'Net', 'Tent', 'Ladder', 'Basketball', 'Anchor' ]
, products = [ { name: 'Trampoline' }, { name: 'Net' },
{ name: 'Tent' }, { name: 'Hoop' }
]
, missing = $.grep(slots, function(product) {
return products.indexOf({ name: product }) < 0 }
)
;
console.log(missing);
Your problem is that you have an array of objects:
var products = [{name:'Trampoline'}, {name:'Net'}, {name:'Tent'}, {name:'Hoop'}];
And you want to search based on a property of these objects. The indexOf method:
compares [...] using strict equality (the same method used by the ===, or triple-equals, operator)
So you won't find what you're looking for unless you have the specific object in hand, just searching based on the property value or an object with the same structure won't work.
jQuery's $.inArray utility function is (AFAIK) just a portability wrapper for JavaScript implementations that don't have an indexOf method in their Array.
You'll need a search function of your own, something like this:
function indexOfByProperty(array, property, value) {
for(var i = 0; i < array.length; ++i)
if(array[i][property] == value)
return i;
return -1;
}
You could also use === if you want to be stricter but that's up to you and what you need the function to do.
If your array is large, you are better off using a map rather than an array
var products = {"Trampoline": {name:'Trampoline'}, "Net": {name:'Net'}, etc..};
products["foo"] returns null
products["Trampoline"] returns {name: 'Trampoline'}
in O(1) time rather than O(n) time
In ES5 you can use Array.some() to drill into nested Objects in an array:
var products = [{name:'Trampoline'}, {name:'Net'}, {name:'Tent'}, {name:'Hoop'}];
var found_ladder = products.some(function(val, idx) {
return val.name === 'Ladder';
});
Javascript in_array function
function in_array (needle, haystack, argStrict) {
// Checks if the given value exists in the array
// * example : in_array('vlado', {0: 'Kevin', vlado: 'van', 1: 'Zonneveld'});
// * returns : false
// * example : in_array('van', ['Kevin', 'van', 'Zonneveld']);
// * returns : true
var key = '', strict = !! argStrict;
if (strict) {
for (key in haystack) {
if (haystack[key] === needle) { return true;}
}
} else {
for (key in haystack) {
if (haystack[key] == needle) { return true; }
}
}
return false;
}

How to determine if object is in array [duplicate]

This question already has answers here:
How do I check if an array includes a value in JavaScript?
(60 answers)
Closed 29 days ago.
I need to determine if an object already exists in an array in javascript.
eg (dummycode):
var carBrands = [];
var car1 = {name:'ford'};
var car2 = {name:'lexus'};
var car3 = {name:'maserati'};
var car4 = {name:'ford'};
carBrands.push(car1);
carBrands.push(car2);
carBrands.push(car3);
carBrands.push(car4);
now the "carBrands" array contains all instances.
I'm now looking a fast solution to check if an instance of car1, car2, car3 or car4 is already in the carBrands array.
eg:
var contains = carBrands.Contains(car1); //<--- returns bool.
car1 and car4 contain the same data but are different instances they should be tested as not equal.
Do I have add something like a hash to the objects on creation? Or is there a faster way to do this in Javascript.
I am looking for the fastest solution here, if dirty, so it has to be ;) In my app it has to deal with around 10000 instances.
no jquery
Use something like this:
function containsObject(obj, list) {
var i;
for (i = 0; i < list.length; i++) {
if (list[i] === obj) {
return true;
}
}
return false;
}
In this case, containsObject(car4, carBrands) is true. Remove the carBrands.push(car4); call and it will return false instead. If you later expand to using objects to store these other car objects instead of using arrays, you could use something like this instead:
function containsObject(obj, list) {
var x;
for (x in list) {
if (list.hasOwnProperty(x) && list[x] === obj) {
return true;
}
}
return false;
}
This approach will work for arrays too, but when used on arrays it will be a tad slower than the first option.
Why don't you use the indexOf method of javascript arrays?
Check this out: MDN indexOf Arrays
Simply do:
carBrands.indexOf(car1);
It will return you the index (position in the array) of car1. It will return -1 if car1 was not found in the array.
http://jsfiddle.net/Fraximus/r154cd9o
Edit: Note that in the question, the requirements are to check for the same object referenced in the array, and NOT a new object. Even if the new object is identical in content to the object in the array, it is still a different object.
As mentioned in the comments, objects are passed by reference in JS and the same object can exist multiple times in multiple structures.
If you want to create a new object and check if the array contains objects identical to your new one, this answer won't work (Julien's fiddle below), if you want to check for that same object's existence in the array, then this answer will work. Check out the fiddles here and in the comments.
Having been recently bitten by the FP bug reading many wonderful accounts of how neatly the functional paradigm fits with Javascript
I replicate the code for completeness sake and suggest two ways this can be done functionally.
var carBrands = [];
var car1 = {name:'ford'};
var car2 = {name:'lexus'};
var car3 = {name:'maserati'};
var car4 = {name:'ford'};
var car5 = {name:'toyota'};
carBrands.push(car1);
carBrands.push(car2);
carBrands.push(car3);
carBrands.push(car4);
// ES6 approach which uses the includes method (Chrome47+, Firefox43+)
carBrands.includes(car1) // -> true
carBrands.includes(car5) // -> false
If you need to support older browsers use the polyfill, it seems IE9+ and Edge do NOT support it. Located in polyfill section of MSDN page
Alternatively I would like to propose an updated answer to cdhowie
// ES2015 syntax
function containsObject(obj, list) {
return list.some(function(elem) {
return elem === obj
})
}
// or ES6+ syntax with cool fat arrows
function containsObject(obj, list) {
return list.some(elem => elem === obj)
}
try Array.prototype.some()
MDN Array.prototype.some
function isBiggerThan10(element, index, array) {
return element > 10;
}
[2, 5, 8, 1, 4].some(isBiggerThan10); // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true
You could use jQuery's grep method:
$.grep(carBrands, function(obj) { return obj.name == "ford"; });
But as you specify no jQuery, you could just make a derivative of the function. From the source code:
function grepArray( elems, callback, inv ) {
var ret = [];
// Go through the array, only saving the items
// that pass the validator function
for ( var i = 0, length = elems.length; i < length; i++ ) {
if ( !inv !== !callback( elems[ i ], i ) ) {
ret.push( elems[ i ] );
}
}
return ret;
}
grepArray(carBrands, function(obj) { return obj.name == "ford"; });
I used underscore javascript library to tweak this issue.
function containsObject(obj, list) {
var res = _.find(list, function(val){ return _.isEqual(obj, val)});
return (_.isObject(res))? true:false;
}
please refer to underscore.js documentation for the underscore functions used in the above example.
note: This is not a pure javascript solution. Shared for educational purposes.
You can just use the equality operator: ==. Objects are checked by reference by default, so you don't even need to use the === operator.
try this, just make sure you're using the correct variable reference in the place of car1:
var i, car, l = cars.length;
for (i = 0; i < l; i++)
{
if ((car = cars[i]) == car1)
{
break;
}
else car = null;
}
Edit to add:
An array extension was mentioned, so here's the code for it:
Array.prototype.contains = Array.prototype.contains || function(obj)
{
var i, l = this.length;
for (i = 0; i < l; i++)
{
if (this[i] == obj) return true;
}
return false;
};
Note that I'm caching the length value, as the Array's length property is actually an accessor, which is marginally slower than an internal variable.
I would use a generic iterator of property/value over the array. No jQuery required.
arr = [{prop1: 'val1', prop2: 'val2'}, {prop1: 'val3', prop2: 'val4'}];
objectPropInArray(arr, 'prop1', 'val3'); // <-- returns true
function objectPropInArray(list, prop, val) {
if (list.length > 0 ) {
for (i in list) {
if (list[i][prop] === val) {
return true;
}
}
}
return false;
}
You could try sorting the array based on a property, like so:
carBrands = carBrands.sort(function(x,y){
return (x == y) ? 0 : (x > y) ? 1 : -1;
});
Then you can use an iterative routine to check whether
carBrands[Math.floor(carBrands.length/2)]
// change carBrands.length to a var that keeps
// getting divided by 2 until result is the target
// or no valid target exists
is greater or lesser than the target, and so on, which will let you go through the array quickly to find whether the object exists or not.
try this ,
You can use the JavaScript some() method to find out if a JavaScript array contains an object.
<script>
// An array of objects
var persons = [{name: "Harry"}, {name: "Alice"}, {name: "Peter"}];
// Find if the array contains an object by comparing the property value
if(persons.some(person => person.name === "Peter")){
alert("Object found inside the array.");
} else{
alert("Object not found.");
}
</script>
EDIT 05/18/2022
The most simple way using ES6:
const arrayContainsObject = <T extends Record<string, unknown>>(array: T[], object: T) => {
return array.some(item => Object.keys(item).every(key => item[key] === object[key]))
}
Use like so:
const arr = [{
prop1: 'value1',
prop2: 'value2'
}]
const obj1 = {
prop1: 'value1',
prop2: 'value2'
}
const obj2 = {
prop2: 'value2',
prop1: 'value1'
}
const obj3 = {
prop0: 'value0',
prop1: 'value1'
}
arrayContainsObject(arr, obj1) // true
arrayContainsObject(arr, obj2) // true, even when props are arranged in different order
arrayContainsObject(arr, obj3) // false
Previous answer, don't use (because the order of props in an object needs to be identical)
const arr = [{
prop: 'value'
}]
const obj = {
prop: 'value'
}
arr.some((e) => Object.entries(e).toString() === Object.entries(obj).toString()) // true
i know this is an old post, but i wanted to provide a JQuery plugin version and my code.
// Find the first occurrence of object in list, Similar to $.grep, but stops searching
function findFirst(a,b){
var i; for (i = 0; i < a.length; ++i) { if (b(a[i], i)) return a[i]; } return undefined;
}
usage:
var product = $.findFirst(arrProducts, function(p) { return p.id == 10 });
This function is to check for a unique field.
Arg 1: the array with selected data
Arg 2: key to check
Arg 3: value that must be "validated"
function objectUnique( array, field, value )
{
var unique = true;
array.forEach(function ( entry )
{
if ( entry[field] == value )
{
unique = false;
}
});
return unique;
}
you can use Array.find().
in your case is going to look like this
carBrands.find(function(car){
let result = car.name === 'ford'
if (result == null){
return false;
} else {
return true
}
});
if car is not null it will return the javaScript Object which contains the string 'ford'
The issue with many of the answers here is that they will NOT find an object in an array that is equal to another object. They will only search for an EXISTING object that has a pointer to it in an array.
Quick fix using lodash to see if ANY equal object is in an array:
import _ from 'lodash';
_.find(carBrands, car1); //returns object if true, undefined if false
Working Plunker using this method: https://plnkr.co/edit/y2YX9o7zkQa2r7lJ
if its possible to use es6
carBrands.filter(carBrand => carBrand.name === carX.name).length > 0
if it's true there is a similarity
You can convert both the JSON objects to string and simply check if the bigger json contains the smaller json.
console.log(JSON.stringify(carBrands).includes(JSON.stringify(car1))); // true
console.log(JSON.stringify(carBrands).includes(JSON.stringify(car5))); // false
You could also a the findIndex
var carBrands = [];
var car1 = {name:'ford'};
var car2 = {name:'lexus'};
carBrands.push(car1);
if (carBrands.findIndex(f => f.name === car1.name) === -1) {
console.log('not contain')
} else {
console.log('contain')
}
if (carBrands.findIndex(f => f.name === car2.name) === -1) {
console.log('not contain')
} else {
console.log('contain')
}

Categories

Resources