Hello I am working in a project to keep learning js wich is in this URL: http://themapapp.herokuapp.com/ and this is the github page: https://github.com/xtatanx/mapApp
In some of the parts of my code I need to check if some property already exists in an array of objects and also I that property value is equal to something, so far the code that I am using to to dis is this one:
// check if property value exist in an array of objects
function searchByValue(value, property, array){
for(var i = 0; i < array.length; i++){
if(array[i][property] === value){
return true;
}
}
return false;
}
And I use it like this:
if(searchByValue('myDestiny', 'id', map.markers)){
map.markers[1].setPosition({
lat: results[0].geometry.location.k,
lng: results[0].geometry.location.A
});
}else{
createMarker(results[0].geometry.location.k, results[0].geometry.location.A, 'myDestiny');
My question is if actually I am doing it the way it is or if I am wrong because I sometime think that the function its not returning the correct value or is not working good, I will appreciate if some of you guys could give me some advice in how to achieve this, or improve it.
EDIT
i finished with something like
Array.prototype.searchBy = function(property, value){
var _property = arguments[0];
var _value = arguments[1];
if(arguments.length === 1){
return Array.prototype.indexOf.apply(this, arguments);
}
for(var i = 0; i < this.length; i++){
if(this[i][_property] === _value ){
return true;
}
}
return false;
};
Didnt used the checkprop part because actually doesnt understood how it works o_O. thank you very much to #GameAlchemist and #jshanley
Your code works well as long as every object in the array you are searching has defined the property you check for. I could see running into a problem otherwise. You might try adding a check that the property is defined before trying to access its value, like this:
function searchByValue(value, property, array){
for(var i = 0; i < array.length; i++){
// check that property is defined first
if(typeof array[i][property] !== 'undefined') {
// then check its value
if(array[i][property] === value){
return true;
}
}
}
return false;
}
I would rather define this function as a method of Array, and why not overload indexOf, that would act as std indexOf with one argument, and as indexOf(value, propertyName, checkProp) with three arguments.
var __oldIndexOf = Array.prototype.indexOf ;
Array.prototype.indexOf = function() {
if (arguments.length==1) return __oldIndexOf.apply(this, arguments);
var value = arguments[0];
var property = arguments[1];
var checkProp = arguments[2];
if (!checkProp) {
for(var i = 0; i < this.length; i++){
if(this[i][property] === value){
return i;
}
} else {
for(var i = 0; i < this.length; i++){
var thisItem = this[i] ;
if (!Object.hasOwnProperty(thisItem, property))
throw('indexOf error : object ' + thisItem + ' has no property ' + property);
if(this[i][property] === value){
return i;
}
}
return -1;
};
so, for your code,
if (searchByValue('myDestiny', 'id', map.markers)) { ...
becomes :
if (map.markers.indexOf('myDestiny', 'id') != -1 ) { ...
and obviously you can store the found index in case you need it.
i think that, in your case, what you meant was rather using the found index :
var destinyIndex = map.markers.indexOf('myDestiny', 'id');
if(destinyIndex != -1){
map.markers[ destinyIndex ].setPosition({
lat: results[0].geometry.location.k,
lng: results[0].geometry.location.A
});
} else {
createMarker(results[0].geometry.location.k, results[0].geometry.location.A,
'myDestiny');
}
Edit : idea of checking that property exists is courtesy of #jshanley
Related
I stored an object in one variable (Consider as datatable).
var data=[{"controlID":"A","currentValue":"10","onChange":"","onClick":""},
{"controlID":"B","currentValue":"5","onChange":"Testing(A,B)","onClick":""},
{"controlID":"C","currentValue":"-5","onChange":"Testing1(A,B)","onClick":""},
{"controlID":"D","currentValue":"","onChange":"Testing2(B,C)","onClick":""},{"controlID":"E","currentValue":"","onChange":"Testing3(C,D)","onClick":""},{"controlID":"F","currentValue":"","onChange":"","onClick":""}];
Now I know the second row key value as B. How to I Get the Third row (i.e., "C" row values)
Am new of this field. Please help us to helpful.
This function will return your index:
var FindIndexOfControlID = function(id, data){
for(var i = 0; i < data.length ; i++){
if( data[i]['controlID'] == id ){
return i;
}
}
};
Usage:
var index = FindIndexOfControlID('C', data);
Live Example
http://jsfiddle.net/urahara/medhgm7b/
NOTE
Alternatively you may also want to implement function that returns index of any specified property and value:
var FindIndexOfProperty = function(value, property, data){
for(var i = 0; i < data.length ; i++){
if( data[i][property] == value ){
return i;
}
}
};
Usage
FindIndexOfProperty('-5', 'currentValue',data); // returns 2
You can return the third row in javascript by simply executing var thirdRow = data[2]. The row will be returned as an object.
I have a JavaScript function what is dig through on object and make a string value to function object.
Have this JSON:
{
"active": true,
"icons": {
"activeHeader": "ui-icon-alert"
},
"animate": {
"duration": 1000, "always": "dMethod"
}
}
I use JSON.parse on this string so I reach options.animate.always as a string with value dMethdod which is actually a name of the method. So I can access this through window[options.animate.always] and I wish to change the options.animate.always from string to method that is pointed to the string.
I make a function for this job:
function SetFunctions(options, functionName) {
var path = functionName.split(".");
var setterObject = options;
for (var k = 0; k < path.length; k++) {
if (setterObject != undefined) {
setterObject = setterObject[path[k]];
} else {
break;
}
}
if (setterObject != undefined && window[setterObject] != undefined) {
setterObject = window[setterObject];
}
}
I call this function with the variable returned from the parse and function name animate.always as value.
The part that find the correct property is worked, but when I set the value of the setterObject the change is not affect the original value.
I'm thinking to build up the reference as string 'options.animate.always = dMethod' and use eval on it, but I really want to avoid using eval function (I know eval is evil :)).
FINAL SOULUTION:
I put answers together and finished my method. Finally become two methods. I comment it and share maybe useful to others:
function ChangeStringToFunction(functionPath, rootObject, separator) {
// functionPath is required parameter
if (functionPath === undefined || functionPath === null) return;
// rootObject is optional. If not supplied the window object will be the base of the search
var localRootObject = rootObject === undefined ? window : rootObject;
// separator is optional. If not supplied the '.' will be the separator
var localSeparator = separator === undefined ? "." : separator;
// split the string reference (example "jui.someObj1.someOjb2"
var pathParts = functionPath.split(localSeparator);
var currentObject = localRootObject;
// exclude the last part
for (var i = 0; i < pathParts.length - 1; i++) {
currentObject = currentObject[pathParts[i]];
// it's useless to go forward if there is no object
if (currentObject === undefined) return;
}
// get the string represent the name of the function (full path could be included)
var currentValue = currentObject[pathParts[pathParts.length - 1]];
// the value must be a string
if (typeof currentValue !== "string") return;
// get the function reference based on the value provided
var functionReference = ResolveFunction(currentValue);
// if the result is not a function it's meaningless to continue
if (typeof functionReference !== "function") return;
// and finally change the string value of the object with the function value represent by our string
currentObject[pathParts[pathParts.length - 1]] = functionReference;
}
function ResolveFunction(functionPath, separator, rootObject) {
if (functionPath === undefined || functionPath === null) return undefined;
var localRootObject = rootObject === undefined ? window : rootObject;
var localSeparator = separator === undefined ? "." : separator;
var pathParts = functionPath.split(localSeparator);
var currentObject = localRootObject;
for (var i = 0; i < pathParts.length; i++) {
currentObject = currentObject[pathParts[i]];
if (currentObject === undefined) break;
}
return typeof currentObject === "function" ? currentObject : undefined;
}
but when I set the value of the setterObject the change is not affect the original value.
Yes, you are only assigning to a variable. That will never change anything else but the variable, since JavaScript does not have pointers.
To change an object, you will have to assign to a property. In your case, you will have to omit the last iteration to get the object which you then assign to:
function SetFunctions(options, functionName) {
var path = functionName.split("."),
setterObject = options;
for (var k=0; setterObject!=null && k<path.length-1; k++) {
setterObject = setterObject[path[k]];
}
var prop = path[k],
fn = setterObject!=null && window[setterObject[prop]];
if (fn) {
setterObject[prop] = fn;
}
}
Btw, I think in your case it might be easier to build a CallFunctions function that directly invokes the function with the name stored in that property, instead of replacing the property value with the method - unless you plan to invoke it very often.
It depends on the level of indirection you want.
If the method will always be called "always", you can do something like this:
function SetFunction(object, propertyName, functionName) {
var functionObj = window[functionName];
object[propertyName] = functionObj;
}
And call it like this:
SetFunction(myObj.animate, "always", myObj.animate.always);
But I suspect you want something a bit more generic?
My aim is to find out if we have at least two different values in an array. How to find out this using pure javascript. By now, I use this funcion, who tells me if there are repeated values in an array...
function verificar(array)
{
var filtrado_arr = array.sort();
var resultados = [];
for (var i = 0; i < array.length - 1; i++) {
if (filtrado_arr[i + 1] == filtrado_arr[i]) {
resultados.push(filtrado_arr[i]);
}
}
if (resultados.length > 0)
{
alert("Repeated results"+resultados+".Unable to send to graph.");
return false;
}
else
{
alert("No repeated measures, we can set graph");
return true;
}
}
But this is not enought, of course.
Using a sort and an extra array seems like an overly expensive way to perform this simple task. What is wrong with the following?
function verificar(arr)
{
for (var i=1; i<arr.length; i++) {
if (arr[i-1] != arr[i])
return true;
}
return false;
}
function verificar(array) {
for(i=1; i<array.length; i++){
if(array[0] !== array[i])
return true;
}
return false;
}
Your code implies that you want to check for duplicates, not verify that you have at leas one unique pair of values as stated in your question.
I'd just add another method to the pool of answers: checking for duplicates using Array.some():
function hasDuplicates(array){
return array.some( function( elm, idx ){
return array.lastIndexOf( elm ) > idx;
});
}
console.log( hasDuplicates([3,4,1,2]) ); // false
console.log( hasDuplicates([3,4,1,3,2]) ); // true
Just check the first value of the array "filitrado_arr[0]" against all of the other values in the array. If one of the values matches the first value of array, you know that there is a repeated value. Here is an example of how you could implement that logic:
function verificar(array){
var repeats = false
for (var i = 1; i < array.length; i++) {
if (array[0] == array[i]) {
repeats = true;
return repeats
}
}
}
However this answer matches the goal implied by the alerts in your original function not the goal in the question itself.
Using the following function, I am searching an array for the existence of a value;
var checkboxValues = ['large-car', 'small-car', 'automatic'];
var carType = ["large-car"];
function searchArray(arguments)
{
var o = {};
for(var i=0;i<arguments.length;i++)
{
o[arguments[i]]=null;
}
return o;
}
if (carType in searchArray(checkboxValues) )
//do something...
This condition works well when carType (which is an array itself) contains only one value but when carType contains multiple values such as,
var carType = ["large-car", "4WD"];
...then the function will return false.
To give some background, what I am trying to do is show or hide map markers (via Google Maps) based on certain conditions,
Automatic
Manual
Small Car
Large Car
4WD
Each of these values is represented as a checkbox. If "Automatic" and "Small Car" are selected, then only shown map markers who contain both those values.
If "Automatic", "Small Car" and "Large Car" are selected then only show values which match those selections.
This works if the carType array contains only a single value but as an individual vehicle may have more than one type as shown above, this is where the function fails.
What's the best way to write the function to allow for comparing multiple values in one array against that of another?
Snippet taken from this answer.
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;
};
And then use it like this:
var checkboxValues = ['large-car', 'small-car', 'automatic'],
carType = ["large-car"],
merged = arrayUnique(checkboxValues.concat(carType));
if (merged.length === checkboxValues.length) {...}
If you need to return the matching elements of two arrays you can do this:
function matchArrays(base, toSearch) {
var returnArray = [];
for (var i = 0; i < toSearch.length; i++) {
if (base.indexOf(toSearch[i]) !== -1) returnArray.push(toSearch[i]);
}
return returnArray;
}
Usage:
var match = matchArrays(checkboxValues, carType); // return "large-car"
Take a look at array_intersect from PHPJS, a reproduction of PHP's array_intersect function in JavaScript.
You can use js functionality to match array.
One ways is to use indexOf() function that return the index of the string if it is found in array or -1 if not found.
var checkboxValues = ["large-car", "small-car", "automatic"];
var carType = ["large-car","automatic","some car"];
function searchMatch(carType) {
var result = new Array();
for(var i=0;i < carType.length;i++) {
// If match found push the match to the result array.
if(checkboxValues.indexOf(carType[i]) != -1){
result.push(carType[i])
}
}
return result ;
}
As a result you will get ["large-car","automatic"];
if you use underscoreJs may look like this
var checkboxValues = ['large-car', 'small-car', 'automatic'];
var carType = ['small-car','automatic'];
var result=_.any(checkboxValues,function(checkbox){
return _.any(carType,function(carT){ return carT==checkbox;});
});
Try this jQuery solution:
<script type="text/javascript">
var checkboxValues = ['large-car', 'small-car', 'automatic'];
var carType = ["large-car"];
if ($.inArray(carType[0].toString(), checkboxValues ) == -1) {
return false;// if not exists
}
</script>
Let's say that I want to search for a value, like 'StackOverflow', in all declared variables in window.
I can do it with this code:
function globalSearch(obj, value) {
for(var p in obj)
if(obj[p] == value)
return(p);
}
globalSearch(window, 'StackOverflow');
This code will return the name of a variable that have this value (or returns nothing).
So, if I have declared a variable with value 'StackOverflow', it will successfully find it.
My problem is that I want to go deeper and search thru window's objects (and its own nested objects) too, to achieve a result like this:
var x = 'StackOverflow' // returns 'x'
var y = { a : 'StackOverflow' } // returns 'y.a'
var z = { a : { b: 'StackOverflow' } } // returns 'z.a.b'
I'm having problems with inherited methods of Objects. Is there a way to do this?
Deep search but without the recursive function calls
Functional recursion has internal stack limits and wastes memory.
Additional features added
Recursive object protection in the form of a searched array; It doesn't use up too much memory of course as the objects are only stored as references.
Return true if the the object itself matches the value. Otherwise it would return '' which would match to false.
Arrays use angle-bracket notation.
The code
function globalSearch(startObject, value) {
var stack = [[startObject,'']];
var searched = [];
var found = false;
var isArray = function(test) {
return Object.prototype.toString.call( test ) === '[object Array]';
}
while(stack.length) {
var fromStack = stack.pop();
var obj = fromStack[0];
var address = fromStack[1];
if( typeof obj == typeof value && obj == value) {
var found = address;
break;
}else if(typeof obj == "object" && searched.indexOf(obj) == -1){
if ( isArray(obj) ) {
var prefix = '[';
var postfix = ']';
}else {
var prefix = '.';
var postfix = '';
}
for( i in obj ) {
stack.push( [ obj[i], address + prefix + i + postfix ] );
}
searched.push(obj);
}
}
return found == '' ? true : found;
}
Problems
Without passing the initial variable name into the function, we can't return the fully qualified variable name from the beginning. I can't think of a solution and I would be surprised if there was one.
Variable names with spaces are valid as the key to an object, as are other invalid variable names, it just means that the value must be addressed using angle-brackets. There are a couple of solutions I can think of. Regex check each variable name to make sure it's valid and use angle-brackets notation if it is not. The overriding problem with this is that the reg-ex is a page long. Alternatively, we could only use angle-brackets but this isn't really true to the OPs original question.
The indexOf call on the array 'searched' might be a bit heavy on very large objects but I can't yet think of an alternative.
Improvements
Apart from cleaning up the code a little, it would also be nice if the function returned an array of matches. This also raises another issue in that the returned array would not contain references to recursive objects. Maybe the function could accept a result format configuration parameter.
This should work. It uses recursion to achieve the result.
function globalSearch(obj, value) {
for(var p in obj)
if(obj[p] == value){
return(p);
}else if(typeof obj[p] == "object" && obj[p] != obj){
var te = globalSearch(obj[p], value);
if(te!=false){ return p + "." + te }
}
return false;
}
Make your solution recursive. If you have an object, call your function again.
function globalSearch(obj, value) {
for(var p in obj) {
if (obj[p] == value) {
return(p);
} else if (typeof obj[p] === "object") {
var recursiveCheck= globalSearch(obj[p], value);
if (recursiveCheck) {
return p + "." + recursiveCheck;
}
}
}
}
globalSearch(window, 'StackOverflow');
I bet most browsers will hit a warning for too much looping.
This code, based on the other answer, allows for all possible value matches to be found.
function globalSearch(startObject, value, returnFirstResult = false) {
var stack = [[startObject,'']];
var searched = [];
var found = new Set();
var isArray = function(test) {
return Object.prototype.toString.call( test ) === '[object Array]';
}
while(stack.length) {
var fromStack = stack.pop();
var obj = fromStack[0];
var address = fromStack[1];
if( typeof obj == typeof value && obj == value) {
if (returnFirstResult) {
return address == '' ? false : address;
}
found.add(address)
}if(typeof obj == "object" && searched.indexOf(obj) == -1){
if ( isArray(obj) ) {
var prefix = '[';
var postfix = ']';
}else {
var prefix = '.';
var postfix = '';
}
for( i in obj ) {
stack.push( [ obj[i], address + prefix + i + postfix ] );
}
searched.push(obj);
}
}
return Array.from(found);
}