In Javascript is there a clever way to loop through the names of properties in objects in an array?
I have objects with several properties including guest1 to guest100. In addition to the loop below I'd like another one that would loop through the guestx properties without having to write it out long hand. It's going to be a very long list if I have to write the code below to results[i].guest100, that is going to be some ugly looking code.
for (var i = 0; i < results.length; i++) {
if (results[i].guest1 != "") {
Do something;
}
if (results[i].guest2 != "") {
Do something;
}
if (results[i].guest3 != "") {
Do something;
}
etcetera...
}
Try this:
for (var i = 0; i < results.length; i++) {
for (var j=0; j <= 100; j++){
if (results[i]["guest" + j] != "") {
Do something;
}
}
}
Access properties by constructing string names in the [] object property syntax:
// inside your results[i] loop....
for (var x=1; x<=100; x++) {
// verify with .hasOwnProperty() that the guestn property exists
if (results[i].hasOwnProperty("guest" + x) {
// JS object properties can be accessed as arbitrary strings with []
// Do something with results[i]["guest" + x]
console.log(results[i]["guest" + x]);
}
}
I think you'll find useful the "in" operator:
if (("guest" + i) in results[i]) { /*code*/ }
Cheers
Related
I was just curious, is it worth to have if condition before looping some array, that in 90% will be array of 1 item?
Code example:
const a = [3];
const aLength = a.length;
if(aLength > 1) {
for(let i = 0; i < aLength; i++) {
func(i);
}
} else {
func();
}
function func(position = 0) {
console.log('hi' + position);
}
I agree with Federico's comment, a single for loop is the most readable in this case.
Also, even though you reuse it, there is not much point to extracting a.length into aLength
const a = [3];
for(let i = 0; i < a.length; i++) {
func(i);
}
function func(position) {
console.log('hi' + position);
}
Warning: very personal perspective down there, you could achieve the same level of clarity with comments too.
Well, unless the single element case has a very specific meaning in your domain. In which case, I would separate them with two functions with very specific names as follows:
const a = [3];
if(a.length > 1) {
handleMultiple(a);
} else {
handleSingleAndWhyItIsASpecialCase(a)
}
handleMultiple(array) {
for(let i = 0; i < array.length; i++) {
func(i);
}
}
handleSingleAndWhyItIsASpecialCase(array) {
func();
}
function func(position = 0) {
console.log('hi' + position);
}
As Hamid said below, you can easily turn it into a oneliner:
[45,63,77].forEach((element, index) => console.log(index));
Consider using forEach instead of map to make your intent clear though.
Write clean code and make everyone happy.
you can eliminate if and loop:
const a=[5,6,3]
a.forEach((value,index)=>console.log('hi'+index));
If reverse == true I want to run one kind of loop, else I want to run another one.
Currently, here is an example of my code:
if (reverse) {
for (var i = 0; i < length; i++) {
...
}
} else {
for (var i = length; i >= 0; i--) {
...
}
}
The code inside is really big, and is quite the same. I could use a function, but this function would have so many params that is not a good choice.
So I've tried to do something like that:
var loopStart1 = startPageIndex;
if (!reverse) {
condition1 = function(i) {
return i < length;
}
increment1 = function(i) {
return ++i;
}
} else {
condition1 = function(i) {
return i >= 0;
}
increment1 = function(i) {
return i--;
}
}
mainLoop: for (var i = loopStart1; condition1(i); increment1(i)) {
But now I have an infinite loop.
Any idea on how to solve this issue?
Why not do it inline?! ;)
var start = startPageIndex;
for (var i = start; (reverse && i >= 0) || (!reverse && i < length); reverse ? --i : ++i) { }
Assuming the specific case is to traverse through an array either backwards or forwards, there are two simple ways to do that.
1) Just conditionally reverse the array before looping, or
2) Use a single loop but conditionally map the loop variable to something else. Something like...
for (var i = 0; i < length; i++) {
var j = i;
if (reverse) {
j = length - (i + 1);
}
// ...then use j instead of i
}
If you want to make it dynamic, I wouldn't use a for loop, but a do..while loop to be easier to customize.
Your main function would just have a simple reverse bool flag and you could just pass that.
Inside that function that you want to depend on the reverse flag, you can use the ternary expression in the condition (x ? y : z)
Makes it clearer to read. In theory you can do it in a for loop directly, using two ternary directions.
do {
//Your actions here, using i as counter
//Here you will do the counter direction change
if(reverse)
i--;
else
i++;
// Use ternary expression if (x ? y : z) in the while condition
// Reads as: If x is true, do y, else do z
// All in one line
} while(reverse ? i>=0 : i<n);
Ideally, in these situations I would consider using iterators.
How about a simple loop function,
Below I've created a simple function called myLoop, were you can pass the length, if it's reversed, and what callback you want for each loop iteration.
eg.
function myLoop(length, reverse, each) {
var index;
if (!reverse) {
for (index = 0; index < length; index ++) each(index);
} else {
for (index = length -1; index >= 0; index --) each(index);
}
}
function show(index) {
console.log("Loop index = " + index);
}
console.log("forward");
myLoop(5, false, show); //normal
console.log("revere");
myLoop(5, true, show); //reversed
I would opt for the same code, just change the array.
var array = ['one', 'two', 'three'];
var reversed = true;
let arrToUse = reversed ? array.reverse() : array;
for (var i = 0; i < arrToUse.length; i++) {
console.log(arrToUse[i]);
}
Check https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions
Primitive parameters (such as a number) are passed to functions by value; the value is passed to the function, but if the function changes the value of the parameter, this change is not reflected globally or in the calling function.
This is what happens when you call increment1(i), outer i in for loop is not changed. To fix it just set i from increment1(i)'s return value.
mainLoop: for (var i = loopStart1; condition1(i); i = increment1(i)) {
I have 2 arrays of the following contents:
var answer = [[2,1],[1,1],[0,0]];
var selectedObject = [[1,1],[0,0],[2,1]];
I want to match the contents of both the arrays. _.Equals is not working for me in the above condition. As the contents being same are not in same position in array.
Is there any easy way to match the contents of above mentioned arrays.
Any demo code, example, or logic will be helpful.
try this way
var baz = [];
angular.forEach(answer, function(key) {
if (-1 === selectedObject.indexOf(key)) {
baz.push(key);
}
});
if(baz.length==0)
{
//Not matched
}
else
{
//matched
}
I don't know about angularjs. But basic logic goes like this,
j=0
for(i=0; i<arr_len; i++){
if(arr1[i] == arr2[i]{
j++;
}
}
if(arr_len == j){
arrays are equal.
}
Finally solved it. Using _.Equals and basic for loop. It was so simple.
if(answerArray.length != selectedAnsArray.length)
{
//wrong answer
return;
}
else
{
for(var x = 0; x < answerArray.length; x++)
{
for(var y = 0; y < selectedAnsArray.length; y++)
{
if(_.isEqual(answerArray[x],selectedAnsArray[y]))
count++;
}
}
if(count==answerArray.length)
{
//correct answer
return;
}
else
{
//wrong answer
return;
}
}
I query a websql database and some of the fields returned have the string-value "undefined".
In a loop, I want to check if the fields have undefined and if so, assign them an empty string as a value.
All works well, except for the assignment. Here's my code:
for (var i = 0; i < result.length; i++) {
for (temp in result[i]) {
if (result[i][temp] == "undefined") {
console.log(typeof(result[i][temp])); // outputs "string" as it should
result[i][temp] = "";
}
}
}
result is an array that contains objects. The code in the if-block is executed except for the assignment, which never takes effect.
What do I need to change?
EDIT:
When I add this immediately after the loop above , it outputs "undefined" for each field that already was undefined before the loop above (hope that makes sense :D).
for (var i = 0; i < result.length; i++) {
for (temp in result[i]) {
if (result[i][temp] == "undefined") {
console.log(result[i][temp]);
}
}
}
I use the whole thing in a callback function, but that shouldnt matter, right? I mean inside a callback function, the code is executed in order just like anywhere else, right?
2nd EDIT:
var arr = [];
arr.push(result[0]); // result currently only holds one object
for (var i = 0; i < arr.length; i++) {
for (temp in arr[i]) {
console.log(arr[i][temp]);
console.log(typeof(arr[i][temp])); // outputs "string" for the undefined fields
if (arr[i][temp] == "undefined") {
arr[i][temp] = "szszsz";
}
}
}
for (var i = 0; i < arr.length; i++) {
for (temp in arr[i]) {
console.log(arr[i][temp]); // still outputs undefined
}
}
ANSWER:
See ArinCool's comment: I copied the array into another array and then I was able to overwrite the fields.
I have an array
var aos = ["a","a","a","b","b","c","d","d"];
I want to know if I can remove just 1 item if it finds 2 or more of the same value in the array. So for instance if it finds
"a", "a"
it will remove one of those "a"
This is my current code:
var intDennis = 1;
for (var i = 0; i < aos.length; i++) {
while (aos[i] == aos[intDennis]) {
aos.splice(i, 1);
intDennis++;
console.log(aos[intDennis], aos[i]);
}
intDennis = 1;
}
NOTE: My array is sorted.
Edited after better understanding of OP use-case.
Updated solution and fiddle test to incorporate suggestion from pst in comments.
(Not for nothing, but this method does not require the original array be sorted.)
Try this...
var elements = [];
var temp = {};
for (i=0; i<aos.length; i++) {
temp[aos[i]] = (temp[aos[i]] || 0) + 1;
}
for (var x in temp) {
elements.push(x);
for (i=0; i<temp[x]-2; i++) {
elements.push(x);
}
}
Fiddle Test
Because you said you have a sorted array, you only need to remove the second time a element is found. You only need one for.
The splice() function returns the removed element so, just use it to not remove more elements of that kind.
This solution is more clean and efficient.
var aos = ["a","a","a","b","b","c","d","d"];
var lastRemoved = "";
for (var i = 1; i < aos.length; i++) {
if (aos[(i-1)] == aos[i] && lastRemoved != aos[i]) {
lastRemoved = aos.splice(i, 1);
}
}
Code tested and working. Result: ["a", "a", "b", "c", "d"]
I don't believe there's any better way to do this on an unsorted array than an approach with O(n^2) behaviour. Given ES5 array-builtins (supported in all modern browsers, though not in IE prior to IE9), the following works:
aos.filter(function(value, index, obj) { return obj.indexOf(value) === index; })
UPDATED ANSWER TO REMOVE ONLY 1 DUPLICATE:
Assuming that each object will resolve to a unique String, here's a potential solution. The first time the object is detected, it sets a counter for that object to one. If it finds that object again, it splices that element out and increments the associated counter. If it finds that element more times, it will leave it alone.
var elements = {};
for (var i = 0; i < aos.length; i++) {
if(elements[aos[i]]){
if(elements[aos[i]] == 1){
aos.splice(i,1);//splice the element out of the array
i--;//Decrement the counter to account for the reduced array
elements[aos[i]]++;//Increment the count for the object
}
} else {
elements[aos[i]] = 1;//Initialize the count for this object to 1;
}
}
Here's the test fiddle for this.
I would not mutate the input -- that is, don't use splice. This will simplify the problem a good deal. Using a new array object here may actually be more efficient. This approach utilizes the fact that the input array is sorted.
Consider: (jsfiddle demo)
var input = ["a","a","a","b","b","c","d","d"]
var result = []
for (var i = 0; i < input.length; i++) {
var elm = input[i]
if (input[i+1] === elm) {
// skip first element (we know next is dup.)
var j = i + 1
for (; input[j] === elm && j < input.length; j++) {
result.push(input[j])
}
i = j - 1
} else {
result.push(elm)
}
}
alert(result) // a,a,b,c,d
Happy coding.
Replace === with a custom equality, as desired. Note that it is the first item is omitted from the output, which may not always be "correct".
REVISED EXAMPLE
function removeDuplicate(arr) {
var i = 1;
while(i < arr.length) {
if(arr[i] == arr[i - 1]) {
arr.splice(i, 1);
}
while(arr[i] == arr[i - 1] && i < arr.length) {
i += 1;
}
i += 1;
}
return arr;
}
alert(removeDuplicate(["a","a","a","b","b","c","d","d"]));