I have two dictionaries (object in JS?), and I want to compare them.
In a while loop, I want to print True if at least one of the pairs is identical (i.e. the dictionary below), as opposed to the whole dictionary being identical (but if the whole dict is identical the statement must still be True obviously):
my_dict = {"Text1":"Text1", "Text2":"Text3", "text5":"text5"}
I know in python it would be like that:
while any(key == value for key, value in my_dict.items()):
...
else:
...
But I can’t get my hands on the correct syntax for JavaScript.
With Object.entries() and some() this is a one-liner:
let my_dict = {"Text1":"Text1", "Text2":"Text3", "text5":"text5"}
let answer = Object.entries(my_dict).some(([key,value]) => key == value);
console.log(answer)
for(var key in obj){
if(key === obj[key]){
//Do Something
} else {
//Do Something Else
}
}
That iterates through the object, and if the key is equal to the value, then it does something, otherwise it does something else.
You can use the some() function on JavaScript arrays which is identical to any from Python I think.
let my_dict = {"Text1":"Text1", "Text2":"Text3", "text5":"text5"}
let same_exists = Object.keys(my_dict).some((key) => key === my_dict[key])
console.log(same_exists)
Related
I have a big array of objects where I need to get the unique values for some keys.
I have the code working, but I would like to understand it.
Object
{
"cor": {
"id": 89,
"code": "192"
},
"tamanho": {
"id": 74,
"code": "L"
},
"price": "56,34",
"prevPrice": "93,90",
"stock": 0
}
And this is the iteration that return only unique values.
What I can't understand is the return statement, how does javasacript reads it?
var tamanhos = [];
data.grelha.filter(function(el, i, arr) {
return tamanhos.indexOf(el.tamanho.id) == -1 && tamanhos.push(el.tamanho.id);
});
Thanks a lot!
Before I get to what I think you're asking, let's talk about .filter(). Firstly, it returns a new array, so calling .filter() without using its return value is not how you are supposed to use it: if you just want to iterate over the array you should use .forEach() instead. It works by calling the function you pass it once per array element. Only elements for which your function returns a truthy value will be added to the output array. The correct way to use .filter() to solve this problem would be something like this:
var tamanhos = data.grelha.map(el) { return el.tamaho.id }).filter(function(el, i, arr) {
return arr.indexOf(el) === i
})
That is, first use .map() to get a list of all the IDs, then use .filter() to only keep elements if they are the first occurrence of that ID in the array, thus setting tamanhos to be an array of unique IDs.
Now to what you seem to be asking, which is for an explanation of what the following line is doing:
return tamanhos.indexOf(el.tamanho.id) == -1 && tamanhos.push(el.tamanho.id);
The key is the && (logical AND) operator. It uses short circuit evaluation, which means that the expression on the right-hand-side of the && will only be evaluated if the expression on the left-hand-side is truthy.
Two simple examples (click "Run"):
true && alert('This WILL display because alert() is called.');
false && alert('This will NOT display because alert() is not called');
So if tamanhos.indexOf(el.tamanho.id) == -1 is true then the tamanhos.push(el.tamanho.id) part will be executed, otherwise the .push() will not be executed. In other words, the part after the return is equivalent to doing this:
if (tamanhos.indexOf(el.tamanho.id) == -1) {
tamanhos.push(el.tamanho.id);
}
(That is, if the item isn't already in the tamanhos array then add it.)
The result of the whole && expression is then returned, but as mentioned above that is not really relevant because you don't use the return value from .filter(). So what your code is doing is equivalent to this:
var tamanhos = [];
data.grelha.forEach(function(el) {
if (tamanhos.indexOf(el.tamanho.id) == -1) {
tamanhos.push(el.tamanho.id);
}
});
this is a json datas. Json values can use array. I think, you know arrays. So Arrays has multi areas. Like :
[val1]
[val1, val2]
[val1, val2, val3]
[val1, val2, val3, .....]
we can take values as column name. Example for c#:
array[] names = new array["mesut", "joa"]
you have javascript arrays
I dont want to push duplicate values into selectedOwners, so in below code user is selecting owner if owner already existed in selectedOwners array i dont want to push , How can i check that to avoid duplicate values in an array ?
ctrl.js
var selectedOwners = [];
$scope.addProcessOwner = function(dataItem){
var selectedOwner = {
fullName: dataItem.fullName,
workerKey: dataItem.workerKey
}
if(selectedOwners.indexOf(selectedOwner) !== -1) {
selectedOwners.push(selectedOwner);
}
console.log('WORKER DATA',selectedOwners);
}
You can use Array.prototype.some method
The some() method tests whether some element in the array passes the test implemented by the provided function.
var isExists = function(e) {
if (e.fullName == selectedOwner.fullName
&& e.workerKey == selectedOwner.workerKey) {
return true;
}
}
if (!selectedOwners.some(isExists)) {
selectedOwners.push(selectedOwner);
}
The use of Array.indexOf is obvious for simple types like strings and numbers.
However, when you are looking for an object, you have to pass the exact same object. A different object with all the same properties and values will still not work. Think of the array as containing pointers to the objects and you must look for the same pointer.
Instead you will need to write your own method to compare the owners for equality and loop through the array doing this check.
Try wrapping your "if" logic in a for-loop .
Example
//Following code loops through array and check for already existing value
for(var i = 0; i < selectedOwners.length; i++){
if(selectedOwners.indexOf(selectedOwner) !== -1) {
selectedOwners.push(selectedOwner);
}
}
I have two objects which I am comparing. I have an array of objects, and I am trying to see if the array contains a certain object. I think it should be finding it, but it is not. Here is the object in the array:
and here is the object I am looking for:
I am using:
if (collection.indexOf(object) !== -1) {
//do something
}
And it returns an index of -1, even though it seems to me that the objects match. Am I missing something here?
try this, if all fields are equals return true
function testContains(arrayOfObject, lookingObject )
var index;
for (index = 0; index < arrayOfObject.length; ++index) {
var o = arrayOfObject[index]);
if(JSON.encode(o)===JSON.encode(lookingObject)) {
return true;
}
}
return false;
}
indexOf() will work only for elementary types like numbers, strings, boolean etc. It does not do deep comparison to match objects.
Something like the following should work:
var found = false;
arr.forEach(function(_object) {
// code to set found to true if _object is what you need
});
// if found is true, your array has your object, else it doesn't
If you can use Lodash (it's really useful and worth it in my opinion) you can use _.find:
_.find(collection, object)
or if you want to only know if the object is present in array, you can do:
_.includes(collection, object)
I optimized #Kaiser'S answer into a one-liner:
var found = obj_list.map(JSON.stringify).indexOf(JSON.stringify(obj)) !== -1;
But, this will only work, if the order of the objects is the same:
The JSON represantation of obj1 = {'a': 1, 'b': 2} wouldn't match obj2 = {'b': 2, 'a': 1}
But if the object you're looking for was copied from the list then the test should work.
Also to take into account, this will only work if the objects in the list are simple objects which can be "stringified".
I am trying to figure out if all of the elements in an array are keys in the object.
var obj = { name: 'Computer', cost: '$1,000' };
var myArray = [ 'name', 'cost', 'bio' ]; //another example would be var myArray = [];
for(var x = 0; x < myArray.length; x++){
if (myArray[x] in obj)
{
return true;
}
}
How can I check if all of the elements in an array are keys in the object?
Do it the other way around. If you find someone in the array who is NOT in the object then you return false. If you reach the end of the loop then you return true because all the keys were in the object.
Depending on what you want, this might do the trick:
function hasKeys(obj, keys) {
for (var i=0; i != keys.length; ++i) {
if (!(keys[i] in obj))
return false;
}
return true;
};
One subtlety you need to ask yourself: do you want to know if the object has the keys directly (i.e. not somewhere in its prototype stack?) If so, then replace keys[i] in obj with obj.hasOwnProperty(keys[i])
function hasKeys(obj, keys) {
return keys.every(Object.prototype.hasOwnProperty.bind(obj));
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every states, "The every method executes the provided callback function once for each element present in the array until it finds one where callback returns a falsy value (a value that becomes false when converted to a Boolean). If such an element is found, the every method immediately returns false. Otherwise, if callback returned a true value for all elements, every will return true. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values" (emphasis mine).
Array.some() makes for a clean solution.
// object in question
var obj = { ... };
// keys that need to be present in the object
var keys = [ ... ];
// iterate through the whitelist until we find a key that doesn't exist in the object. If all exist, that means Array.some() is false.
var valid = !keys.some(function(key) {
return !obj.hasOwnProperty(key);
});
An alternative solution would be using a similar concept, but with Array.every(). It is to note that this will generally be slower because it always has to touch every element in the whitelist.
// iterate through the whitelist, making sure the object has each key.
var valid = keys.every(obj.hasOwnProperty);
This problem can be expressed in terms of set inclusion: does the set of property keys completely include the array of required keys? So we can write it as
includes(Object.keys(obj), arr)
So now we just need to write includes.
function includes(arr1, arr2) {
return arr2.every(function(key) {
return contains(arr1, key);
}
}
For contains, we could use Underscore's _.contains, or just write it ourselves:
function contains(arr, val) {
return arr.indexOf(val) !== -1;
}
If we are interested in conciseness at the possible expense of readability, we could shorten our definition of includes to use Function#bind instead of the anonymous function:
function includes(arr1, arr2) {
return arr2.every(contains.bind(0, arr1));
}
Now we have functions we can use for other things, instead of mixing up the two different aspects of the problem--the keys of an object, and set inclusion. If we really want to write an all-in-one function, it becomes the somewhat more readable:
function hasMany(obj, arr) {
return arr.every(_.contains.bind(0, Object.keys(obj));
}
If we want more readability, like we were writing a novel:
function object_has_required_keys(object, required_keys) {
var object_keys = Object.keys(object);
function key_is_present(key) {
return object_keys.indexOf(key) !== -1;
}
return required_keys.every(key_is_present);
}
Underscore's _.intersection
If we're lazy (or smart), we could use Underscore's _.intersection to implement includes:
function includes(arr1, arr2) {
return _.intersection(arr1, arr2).length === arr2.length;
}
The idea is to take the intersection, and if the first array includes the second entirely, then the intersection will contain all the elements of the second array, which we can check by comparing their lengths.
Using ES6 sets
Thinking ahead to ES6, we could implement include using its sets, which ought to be faster:
function includes(arr1, arr2) {
var set = new Set(arr1);
return arr2.every(Set.prototype.has.bind(set));
}
I am writing one function on Javascript which needs to address all the anynymous types in a JSON object.
For example,
Typed= {
emails: [{email:'a#a.com'}, {email:'b#a.com'}, {email:'c#a.com'}, {email:'d#a.com'}]
};
is an example of typed array in a JSON because each element inside the array is typed email
while,
Anon= {
emails: ['a#a.com', 'b#a.com', 'c#a.com', 'd#a.com']
};
is a JSON object where emails is collection of some anonymous objects.
Is there any ways that I can differentiate between both in JQuery or Javascript?
The simplest solution is to have the JSON source only return one of the two forms. Then you don't have to branch in your client.
If that's not an option, you could get the values out with JavaScript's handy lazy-evaluation of boolean expressions:
var em = json.emails[0].email || json.emails[0];
That statement will prefer the array-of-objects version, but use the array-of-strings version as a fallback.
(edited in response to clarifying comment below)
You can determine what properties a JS object has at runtime like this:
function enumerate(targetObject){
var props = [];
for (var propName in targetObject ){
props.push(propName);
}
return props;
}
console.log(enumerate({foo:1, bar:'baz'}),join(',')); //"foo, bar"
you could then modulate your logic on the basis of the properties you get back. You'll want to make sure you understand prototypes (specifically what Object.hasOwnProperty does and means), too.
You can use Array iteration methods to quickly check if all (or some) elements of the array have the desired type:
Anon.emails.every(function(e) { return typeof e == "object" }) // false
Typed.emails.every(function(e) { return typeof e == "object" }) // true
or a more generic solution
typeCheck = function(type) {
return function() {
return typeof arguments[0] == type
}
}
Anon.emails.every(typeCheck("object")) // false
Typed.emails.every(typeCheck("object")) // true
(An obligatory warning about iteration methods not being supported in ancient browsers)
How about this:
var istyped = function (a) {
if (typeof(a) !== 'object') {
return false;
}
var count = 0;
for (var key in a) {
count = count + 1;
}
return (count === 1);
}
I'm assuming here you just want to distinguish between regular variables (this would be your anonymous variable) and objects with just one key/value pair inside (this would be your typed variable).
To check if array contains only typed variables you'd just have to loop through it with that function. For example (in newer versions of JavaScript):
Typed.emails.every(istyped) = true
Anon.emails.every(istyped) = false
Why not do a map first:
emails = emails.map(function (email) {
if (typeof email.email === 'string')
return email.email;
});
That will make your emails array an array of just strings. Then you can just process it as usual. There aren't any side-effects if it is an array of strings (email.email will be undefined).
I do stuff like this when I have to make one client deal with multiple versions of an API. Alternatively, you could do the map the other way:
emails = emails.map(function (email) {
if (typeof email === 'string')
return {email: email};
});
This would work better if there could be other information in each object in your emails array.