Up/Down counter

Hi,
I need to generate a counter which counts up to 10 and back to 0.

The following function does't work so, I appreciate some help.
TIA

var dir = 0;
var count = context.get("counter") || 0;
if(dir === 0){
    count = (count+1);
    context.set("counter", count);
    if(count === 11){
    dir = 1;
    } 
    msg.payload = count;
    return msg;
}
if(dir === 1){
    count = (count-1);
    context.set("counter", count);
    if(count === 0){
    dir = 0;
    }     
    msg.payload = count;
    return msg;
}

Your dir variable is local to the function and will always be 0.

You should get/set it from context in the same way you are storing the counter variable.

You mean this way? I'm still doing it wrong!

var dir = context.get("dir") || 0;
var count = context.get("counter") || 0;
if(dir === 0){
    count = (count+1);
    context.set("counter", count);
    if(count === 11){
    context.set("dir", dir);
    dir = 1;
    } 
    msg.payload = count;
    return msg;
}
if(dir === 1){
    count = (count-1);
    context.set("counter", count);
    if(count === 0){
    context.set("dir", dir);
    dir = 0;
    }     
    msg.payload = count;
    return msg;
}

You are saving dir back to context before you change its value.

Got it. Thank you!

If you remove the two lines

    msg.payload = count;
    return msg;

from inside each if statement and put them right at the end that will be a bit more efficient. Also if before the return you add

  context.set("dir", dir);
  context.set("counter", count);

then you can remove all of those from earlier too. It is often a good idea to make sure you only have one return in a function, at the end, and get all context values right at the start and save them all right at the end, then they are much less likely to get forgotten. It may sometimes mean you are unnecessarily saving values but the overheads are trivial, and you will be much less likely to have bugs. Forgetting to write values back to context is very easy to do.
Finally the second if would be better as an else.

If you make the changes as Colin suggests, the second if must be changed to an else if.

And if you want to write some code that you look and think how nice it is then instead of using 0 and 1 for dir use -1 and 1. Then you can add it to count rather than testing to see what you need to do. When the value gets to the min or max you can negate dir.

Actually else I think. But you are right, as initially posted my 'improvement' is anything but.

Thank you!! I modified the code as suggested and works as well but with fewer lines.

var dir = context.get("dir") || 1;
var count = context.get("counter") || 0;
count = (count+dir);
if(count === 11){
dir = -1;
} 
else if(count === 0){
dir = 1;
}     
msg.payload = count;
context.set("dir", dir);
context.set("counter", count);
return msg;
1 Like

Or maybe even

var dir = context.get("dir") || 1;
var count = context.get("counter") || 0;
count = (count+dir);
if((count-5.5)*dir >= 5.5){
  dir = -dir;
} 
msg.payload = count;
context.set("dir", dir);
context.set("counter", count);
return msg;

But maybe that is getting a bit too obtuse.

Now, that's getting very fancy :wink:

I didn't like that one much, it was clever but not pretty, this is much nicer.

var count = ((context.get("counter") || 0) + 1) % 20
msg.payload = count <= 10 ? count  :  20 - count
context.set("counter", count);
return msg;

That counts up to 10 which is what was originally asked for, if you actually want up to 11 which is what the solutions have been doing so far then change the 20s to 22 and the 10 to 11.

2 Likes

Amazing!! :scream:

Well, I'm using the counter to gradually light up a LED bar composed of 10 LEDs. So, the counter should start at 0 (all LEDs OFF) and count up to 10 (all LEDs ON). The detection of 11 is to reverse the count. Depending of the speed, a moving wave is created with the lighting of the LEDs.

We went from 16 lines of coding to only 4. Outstanding!!

Thank you again.

Well,,,sometimes the cost will be loss of readability, @Colin is for sure showing a very compact and brilliant code but it might be difficult to read & understand at first glance. But clever, indeed!!! All my credits

A related question when spending time in making code compact like this, will there be any performance or less memory consumption or other benefits? I mean if you write code in a compiled language, the compiler will anyway optimize your code. But what with javascript in NR? Will node.js optimize anyhow in some way?

I agree, often compact code can be difficult to understand, and my earlier go with the relatively complex arithmetic and comparing to non-obvious numbers like 5.5 falls into that category. The latest one though is not complex, in fact I would argue it is simpler than the the original code with a direction flag and the logic to decide whether to count up or down. It removes a context variable which is a good thing.
The logic is very simple it creates a counter going from 0 to 19 by using modulus 20 and then if the count is <= 10 it returns that, if it is > 10 it returns 20 - the count, so as count goes up 11 to 19 the returned value goes down again from 9 to 1.
In terms of run time efficiency I suspect the last one might just beat the others, but I imagine the difference will be very small.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.