Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Traditional For loop (i.e., step through a sequence)


  • Please log in to reply
18 replies to this topic
nimda
  • Members
  • 4368 posts
  • Last active: Aug 09 2015 02:36 AM
  • Joined: 26 Dec 2010
Ada, ALGOL, BASIC, C, C++, C#, DWScript, F#, Go, Java, Logo, OCaml, Pascal, Perl, PicoLisp, PureBasic, Seed7, Tcl, and more use For to step through a sequence like -6 to 6
D has foreach()
Forth omits uses do after the fact ("7 -6 do")
Fortran and REXX use Do
Python uses for with range()
Ruby uses do like this: "-6.upto(6) do |h|"
Sather has .upto
Smalltalk uses to: and do: ("-6 to: 6 do: [ :h |]")
(that's a lotta' langs!)

AutoHotkey stands out from all of these, having no provision for this type of loop. Instead, we initialize a counter and use a While loop.
I don't know how hard it would be to code, but Loop already does this with A_Index and 1 to loop's param.

I would like either a keyword Do or for For to be extended :wink:

Tuncay
  • Members
  • 1945 posts
  • Last active: Feb 08 2015 03:49 PM
  • Joined: 07 Nov 2006
This is easily solved via a function, which generates a range on the fly.
#NoEnv 
SendMode Input 
SetWorkingDir %A_ScriptDir%

For k,v in range(3, 5)
    MsgBox %v%

For k,v in range(1, 4)
    MsgBox %v%

s := ""
For k, v in range(-3, 6)
    s .= k "=" v "`n"
MsgBox % s

s := ""
For k, v in range(3, -6)
    s .= k "=" v "`n"
MsgBox % s

range(from, to)
{
    range := {}
    if (from < to)
        While, (from <= to)
            range[A_Index] := from++
    else
        While, (from >= to)
            range[A_Index] := from--
    return range
}
Usage is easy, just ignore the k part (which is A_LoopIndex) and use the second variable. Not exactly the same as in Python, but close.

(Should I post this function in the Scripts & Functions sub-forum?)

Edit: Updated the code and made optional parameter to required one. There was some problems... keep it simple.

Or you reverse the objects keys with values, so the value is index and the keyname is range value. In this case For k in range(1, 4) is enough, no ignoring of second value.

#NoEnv 
SendMode Input 
SetWorkingDir %A_ScriptDir%

For k in range(3, 5)
    MsgBox %k%

For k,v in range(1, 4)
    MsgBox %k%

s := ""
For k, v in range(-3, 6)
    s .= k "=" v "`n"
MsgBox % s

s := ""
For k, v in range(3, -6)
    s .= k "=" v "`n"
MsgBox % s

range(from, to)
{
    range := {}
    if (from < to)
        While, (from <= to)
            range[from++] := A_Index
    else
        While, (from >= to)
            range[from--] := A_Index
    return range
}

No signature.


!hugov
  • Guests
  • Last active:
  • Joined: --
@tuncay, perhaps add a step?
#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%

s := ""
For k, v in range(10, 0, -2)
    s .= k "=" v "`n"
MsgBox % "range(10, 0, -2)`n" s

s := "" ; same as above
For k, v in range(10, 0, 2)
    s .= k "=" v "`n"
MsgBox % "range(10, 0, 2)`n" s

s := ""
For k, v in range(3, 5)
    s .= k "=" v "`n"
MsgBox % "range(3, 5)`n" s

s := ""
For k,v in range(0, 10, 2)
    s .= k "=" v "`n"
MsgBox % "range(0, 10, 2)`n" s

s := ""
For k,v in range(4)
    s .= k "=" v "`n"
MsgBox % "range(4)`n" s

s := ""
For k, v in range(-3, 6)
    s .= k "=" v "`n"
MsgBox % "range(-3, 6)`n" s

s := ""
For k, v in range(3, -6, 2)
    s .= k "=" v "`n"
MsgBox % "range(3, -6, 2)`n" s

ExitApp
Esc::ExitApp

range(from, to="", step=1)
{
   if (to="")
   {
      to := from
      from := 1
   }
   Step:=Abs(Step)
   range := {}
   if (from < to)
      While, (from <= to)
       {
        range[A_Index] := from
        from += step
       }  
   else
      While, (from >= to)
       {
        range[A_Index] := from
        from -= step
       } 
   return range
}


Tuncay
  • Members
  • 1945 posts
  • Last active: Feb 08 2015 03:49 PM
  • Joined: 07 Nov 2006
Good idea hugov. Here same without Abs() (instead -step is enough) and direct access to object example. Also updated to be able to get a string list, instead of an object:

#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%

3to5 := range(3, 5)
MsgBox % 3to5[2]
MsgBox % range(3, 5, 1, "`n")

from := -9
to := 10
MsgBox % range(from, to)[19]
MsgBox % range(from, to, 1, ",")

s := ""
For k,v in range(10)
    s .= v . "`n"
MsgBox % s

s := ""
For k,v in range(-3, 2)
    s .= v . "`n"
MsgBox % s

s := ""
For k,v in range(2, 5, -2)
    s .= v . "`n"
MsgBox % s

s := ""
For k,v in range(5, -2, 2)
    s .= v . "`n"
MsgBox % s

range(from, to="", step=1, delim="")
{
    if (to = "")
        to := from, from := 1
    if (step < 0)
        step := -step
    if (delim != "")
    {
        range := ""
        if (from > to)
            While (from >= to)
                range .= from . delim, from -= step
        else
            While (from <= to)
                range .= from . delim, from += step
        StringTrimRight, range, range, % StrLen(delim)
    }
    else
    {
        range := {}
        if (from > to)
            While (from >= to)
                range[A_Index] := from, from -= step
        else
            While (from <= to)
                range[A_Index] := from, from += step
    }
    return range
}

No signature.


  • Guests
  • Last active:
  • Joined: --
Sweet - I'd replace
StringTrimRight, range, range, % StrLen(delim)
with
Range:=RTrim(Range, delim)
and post the func in the Scripts sections if I were you

Tuncay
  • Members
  • 1945 posts
  • Last active: Feb 08 2015 03:49 PM
  • Joined: 07 Nov 2006

and post the func in the Scripts sections if I were you

I am working on it. I add documentation and make some test cases to be sure it works correct.

Why RTrim()? I remove the number of characters from the list, which may vary depending on the size of delim. In fact, I just remove last delimiter, which is added from the Loop.

No signature.


  • Guests
  • Last active:
  • Joined: --

Why RTrim()?

I understand why, but RTRim is one less function to call as it skips the StrLen() and RTrim only removes the characters from the delimter, try it with
MsgBox % range(3, 5, 1, "-DELIMITER-")
But is doesn't matter that much, StringTrimRight just looks old in this modern looking code I think
perhaps
SubStr(range,1, (StrLen(Delim)*-1))
looks more modern ;-)
(StringTrimRight might be removed/replaced from ahk v2 if I recall correctly so that might be one reason although not a very compelling one)

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
On-topic: I don't see any particular need for another loop command.

Off-topic: RTrim("Unlimited-delimiter-", "-delimiter-") removes the trailing -, d, e, l, etc. and returns "Un". I doubt that's what you want. Also, StringTrimRight has already been removed from v2.

Seidenweber
  • Moderators
  • 638 posts
  • Last active: Sep 06 2015 01:51 PM
  • Joined: 10 May 2011

On-topic: I don't see any particular need for another loop command.

a few billion years B.C... Two water living creatures meet at the coast. Says one "If we had legs, we could go to land". Says the other "I don´t see any particular need for legs". At this day the evolution of snails and worms began.

All questions & answers are related to AHK 1.1.19.03 x64 Unicode

 


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
To this day, snails and worms don't have legs. Obviously they were right; they didn't need legs. :roll:

The survival of the human race does not depend on this feature. We'll get along just fine with the tried and true Loop command.

rbrtryn
  • Members
  • 1177 posts
  • Last active: Sep 11 2013 08:04 PM
  • Joined: 22 Jun 2011
Getting back on topic...

There is no need to add another loop command or use objects. A simple function seems to do the trick:
While InRange( index, 0, 10, 2 ) {
	ToolTip % index
	sleep 500
	}
Return

InRange( ByRef index, from, to, step = 1 )
	{
		; Error checking
		n := from + to + step
		ErrorLevel := 1
		If n is not number
			Return False
		If ( A_Index = 0 )
			Return False

		ErrorLevel := 0		
		If ( step = 0 )
			Step := 1
		
		index := step * (A_Index - 1) + from
		if ( step < 0 ? index < to : index > to )
			Return False
		Else 
			Return True
	}


nimda
  • Members
  • 4368 posts
  • Last active: Aug 09 2015 02:36 AM
  • Joined: 26 Dec 2010
Which needs to be posted at the bottom of any task-solution or Ask for Help reply, negating its usefulness to the point where nobody will ever use it :roll:

rbrtryn
  • Members
  • 1177 posts
  • Last active: Sep 11 2013 08:04 PM
  • Joined: 22 Jun 2011

Which needs to be posted at the bottom of any task-solution or Ask for Help reply, negating its usefulness to the point where nobody will ever use it :roll:

Which post were you responding to?

nimda
  • Members
  • 4368 posts
  • Last active: Aug 09 2015 02:36 AM
  • Joined: 26 Dec 2010
Yours

rbrtryn
  • Members
  • 1177 posts
  • Last active: Sep 11 2013 08:04 PM
  • Joined: 22 Jun 2011
@nimda Are you claiming that my solution doesn't work or are you claiming that every problem has to be solved by adding a new command to the language?

The solution posted works for integer and floating point numbers. It also allows for positive or negative steps. I don't see the problem.