var uniqueProperties = [];
for (var i = 0, length = obj.length; i < length; i++) {
for (var prop in obj[i]) {
if (prop == null || prop == ' ') {
delete obj[i][prop];
}
}
for (var prop in obj[i]) {
if (this.uniqueProperties.indexOf(prop) === -1) {
this.uniqueProperties.push(prop);
}
}
}
I want to first delete the keys with null or blank values, and then add them in the array and check its length.
I think its not getting deleted.
In the first loop, you're checking to see if "prop" is null or (incorrectly) the empty string, but that doesn't really make sense. You should be checking the value of that property of "obj[i]":
if (obj[i][prop] == null || obj[i][prop] == '')
delete obj[i][prop];
Also, your "uniqeProperties" list should also be "assisted" by a separate object so that you can avoid the poor algorithmic performance of repeated linear scans:
var uniqueProperties = [], uniqueMap = {};
// ...
for (var prop in obj[i]) {
if (!this.uniqueMap[prop]) {
this.uniqueMap[prop] = true;
uniqueProperties.push(prop);
}
}
Why do you want to delete the keys....
for (var key in object) {
if (!object.hasOwnProperty(key)) {
continue;
} //to skip inherited properties
if (!key[object]) {
continue;
} //skip null or blank values
}
delete obj[i][propertyName] is a bad coding practice. You shouldn't delete properties directly in your incoming data since the results can sometimes be unpredictable and cause lots of headaches in the debugging stage.
Related
I've got an array that has a lot of objects and embedded arrays. I need to iterate through the entire array to see if anything is empty or null. My problem is checking Arrays and whether or not the arrays return empty. I keep getting object arrays and they are not null or undefined so get added in even if length is 0. What I've got so far.
var progressCount = 0;
var progressKeyLength = progressBarCriteria.length;
for (var i = 0; i<progressKeyLength; i++){
//I can find the arrays here but still not able to check length since they are actually object arrays.
if(Array.isArray(progressBarCriteria[i])){
console.log('array' + i);
}
if (progressBarCriteria[i] !== null && progressBarCriteria[i] !== ""){
++progressCount
}
}
progressBarCritiria = [
example1: "",
example2: "asdasdas",
example3: 233,
example4: {asda: 1},
example5: {asadasda: "asdasdA"},
example6: "",
example7: [],
example8: [1, 12312],
example9: [{1: "ad"}, {1: 12312}],
]
So 1, 6 and 7 should not be added to my count.
If you need to check the length or null value for an array, you can think about the Truthy - Falsy value as follow:
if (Array.isArray(progressBarCriteria[i]) && progressBarCriteria[i].length) {
// This is an array and is not empty.
}
This Array.isArray(progressBarCriteria[i]) checks if that value is an array.
If this progressBarCriteria[i].length is 0 the boolean value will be false, ortherwise will be true.
You can use a recursive function to do that. It is important to notice that in javascript arrays are objects. So you need to check for objects by if (typeof arr === 'object' && !(arr instanceof Array)). For more informations check this and this.
function recursive_array_chekc (arr) {
//check if arr is an object
if (typeof arr === 'object' && !(arr instanceof Array)) {
//check if object empty
if (Object.keys (arr).length === 0) {
//do something if empty
console.log ('this object is empty');
} else {
//check object properties recursivly
for (var key in arr)
if (arr.hasOwnProperty (key))
recursive_array_chekc (arr[key])
}
} else
if (Array.isArray (arr)) {
//check if array is empty
if (arr.length === 0) {
//do something if empty
console.log ('this array is empty');
} else {
//check array elements recursivly
for (var i = 0; i < arr.length; i++)
recursive_array_chekc (arr[i])
}
}
}
I was able to look at both answers and came up with this working solution. This is using Typescript so sorry for confusion.
for (var i = 0; i<progressKeyLength; i++){
if (!(progressBarCriteria[i] instanceof Array)){
if(progressBarCriteria[i] !== null && progressBarCriteria[i] !== "") {
++progressCount
}
} else {
let current = progressBarCriteria[i];
if (Array.isArray(current) && current.length !== 0){
++progressCount
}
}
}
This is my array of objects:
var data = [
{
"label": "HOME",
"href": "web-tutor99.com",
"children": [{}]
},
{
"href": "web-tutor99.com",
"label": "HTML5"
}
];
It is a multidimensional object and here the children property is empty. How can I find empty properties like this and remove them using jQuery?
Try this
data = [{
"label": "HOME",
"href": "web-tutor99.com",
"children": [{}]
}, {
"href": "web-tutor99.com",
"label": "HTML5"
}];
alert("Before : "+JSON.stringify(data));
//console.log(data);
checkEmptyObj(data);
alert("After : "+JSON.stringify(data));
function checkEmptyObj(data) {
$.each(data, function(key, value) {
if ($.isPlainObject(value) || $.isArray(value)) {
checkEmptyObj(value);
}
//alert(key+":"+$.isEmptyObject(value));
if (value === "" || value === null || $.isEmptyObject(value)) {
delete data[key];
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You could do this..
for (var i in data) {
if (test[i].children === null || test[i].children === undefined || test[i].children.length<=0) {
delete test[i].children;
}
}
But I see no practical use in wasting CPU cycles looping through objects to remove empty objects.
Not really sure what you're trying to achieve. But you're better off just checking if its empty, and then not displaying if its the case.
You could simply create a (if nested, recursive) function looping through all elements and check if the it has a value, if not, delete that property.
In your example object you have the problem that the children property is by far not empty - it is a property with a value of an array containing one empty object. Depending on your scenario you'd have to run through your object multiple times, removing empty entries step by step (could probably do some optimization).
As a final note, you can use for...in to loop through an object's properties and for...of to loop through an object's/array's values.
I think the following pure JS snippet takes care of the job. You can check it # JSBin
var data = [{"label":"HOME","href":"web-tutor99.com","children":[{}]},{"href":"web-tutor99.com","label":"HTML5"}];
function walkJSONObj(obj){
for (var prop in obj) {
if (obj[prop].constructor === Array) { //if prop is an array
walkJSONArray(obj[prop]); //go walk through the arrays
obj[prop].length === 0 && delete obj[prop]; //if on return the array is empty delete it
}
else typeof obj[prop] === 'undefined' && delete obj[prop]; //delete undefined props
}
}
function walkJSONArray(arr){
for (var l = arr.length-1; l >= 0; l--) {
walkJSONObj(arr[l]); // go walk the item objects
if (Object.keys(arr[l]).length === 0 && JSON.stringify(arr[l]) === JSON.stringify({})) {
arr.splice(l, 1); // if on return the object is empty delete it
}
}
}
walkJSONArray(data);
I start with 2 string arrays:
var ny_students = [......];
var la_student = [.....];
I've got this bit of code that adds to the array:
for (i=0;i<array.length;i++) {
if (ny_students.contains(array[i]["Result"])){
array[i].Class = "Advanced";
}
else{
if (la_students.contains(array[i]["Result"])){
array[i].Class = "General";
}
else{
if (i==0) {
array.splice(i,1);
}
else {
array.splice(i-1,1);
}
i--;
}
}
}
I am getting unexpected results; the 'key' value somehow becomes 'contains'. Here is the 'contains' method definition:
Array.prototype.contains = function ( needle ) {
for (i in this) {
if (this[i] == needle) return true;
}
return false;
}
Adding to the Array.prototype the way you have will make the contains function enumerable and thus appear in the for...in loop
This is why you never use for...in on an array
Alternatively, define contains in such a way that is is not enumerable
Object.defineProperty(Array.prototype, 'contains', {
configurable: true,
value: function ( needle ) {
for (var i = 0; i < this.length; i++) {
if (this[i] == needle) return true;
}
return false;
}
});
The for...in syntax in JS iterates over "iterable" properties of objects, and there is no promise that they'll be returned in order. Sadly enough, the creators of JS didn't think things through and made the "length" property iterable. So we're stuck with using the lame syntax:
for(var i=0; i<arr.length; ++i) { ... }
You don't need your own contains method because arr.indexOf(n) will return -1 if the value n isn't found. So just do if(arr.indexOf(n) !== -1) to check if a value is in the array.
Finally, the array has a concat method which can combine two arrays (not sure if that will be useful to you in that code, but it's worth pointing out). So if you need to check if a value is in one of two arrays, you could just do :
if(arr1.concat(arr2).indexOf(n) != -1) { ... }
Note that the elements of arr2 don't get added to arr1 when you do that - it actually returns a new array which contains the elements of both arrays.
I have an array that shows this value "135_1,undefined,undefined"
I have to find the "undefined" in the above array and then replace it with "0_0".Undefined can occur multiple times in the array.
I used
var extra = myVariable.replace("undefined", "0_0");
alert(extra);
but then I have to use this three times so that every single time it can search one and replace it.
I have also used this::
for (var i = 0; i < myVariable.length; i++) {
alert(myVariable[i]);
myVariable[i] = myVariable[i].replace(/undefined/g, '0_0');
}
alert(myVariable);
but it did'nt solved my purpose.
String.prototype.replace is a method accessible to strings. undefined is not a string.
This might help you.
for (var i=0, len=arr.length; i<len; i++) {
if (arr[i] === undefined) {
arr[i] = "0_0";
}
}
alert(JSON.stringify(arr));
You could also use Array.prototype.map for this. Note, it only works in IE >= 9
arr = arr.map(function(elem) {
return elem === undefined ? "0_0" : elem;
});
Since the question is tagged with jquery you can use $.map():
var extra = $.map(myVariable, function(item) {
return item || '0_0';
}
This will return a new array whereby each item comprising (in your case) an empty string or undefined is replaced by '0_0'.
var arr = ['135_1',undefined,undefined];
while(arr.indexOf(undefined) != -1) {
pos=arr.indexOf(undefined);
arr[pos]='0_0';
}
Say I have this object:
{
"prop1":"Hello",
"prop2":{
"prop1":{
"prop1":"Tablecloth",
"prop2":"Indians"
},
"prop2":"JuicyJuice"
},
"prop3":"Sponge",
"prop4":{"Bob":"Squarepants"}
}
I would like a recursive function that will return HelloTableclothIndiansJuicyJuiceSpongeSquarepants.
Whatever object I put it, I want it to cycle though until it gets all of the strings and adds them all up.
Thank you!
Here's a very simple implementation that should work for simple objects like this:
var walkProps = function(obj) {
var s = "";
for(var x in obj)
{
if(typeof obj[x] === "string")
s += obj[x];
else
s += walkProps(obj[x]);
}
return s;
}
Demonstration
Note, though, that that depends on the order in which for-in visits the properties on the object, which is not specified and can vary by engine and by how the object is constructed (for instance, the order in which the properties were added).
Update: With some slight modification, this can be used to return the values based on the alphabetical order of the keys. This method is not sensitive to implementation-dependent ordering of properties:
var walkProps = function(obj) {
var s = "", i = 0, keys = Object.keys(obj).sort(), i;
for(; i < keys.length; i++)
{
if(typeof obj[keys[i]] === "string")
s += obj[keys[i]];
else
s += walkProps(obj[keys[i]]);
}
return s;
}
So even if "prop3" comes before "prop2" it will still return the same output.
Demonstration
You would need to write a function that loops over an object's properties and see if they are a string, and then append the strings to an output. If the property is an object rather than a string, you would want to call the function on this object and append it's return value to your total output.
You can loop over an object's properties using for...in like:
var MyObject = {
'a': 'string1',
'b': 'string2'
};
for (var key in MyObject) {
var value = MyObject[key];
}
To check if a property is a string you would want to do:
typeof value === "string"
Which will return true/false accordingly.
As mentioned, for( var b in a ) may not preserve ordering:
// Return array of string values
function getStrings(a) {
if( typeof(a) == "string" ) return [a];
var list = [];
for( var b in a ) list = list.concat(getStrings(a[b]));
return list;
}
Applied to OP's data:
var a = {
"prop1":"Hello",
"prop2":{
"prop1":{
"prop1":"Tablecloth",
"prop2":"Indians"
},
"prop2":"JuicyJuice"
},
"prop3":"Sponge",
"prop4":{"Bob":"Squarepants"}
}
getStrings(a).join(); // "Hello,Tablecloth,Indians,JuicyJuice,Sponge,Squarepants"
// Or as asked for by OP (again, order is not guaranteed)
getStrings(a).join(''); // "HelloTableclothIndiansJuicyJuiceSpongeSquarepants"