Lucky and even lucky numbers

Revision as of 22:07, 16 April 2016 by rosettacode>Gerard Schildberger (→‎{{header|REXX}}: changed/added comments and whitespace, changed indentations.)

Note that in the following explanation list indices are assumed to start at one.

Lucky and even lucky numbers is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
Definition of lucky numbers

Lucky numbers are positive integers that are formed by:

  1. Form a list of all the positive odd integers > 0
  2. Return the first number from the list (which is 1).
  3. (Loop begins here)
    • Note then return the second number from the list (which is 3).
    • Discard every third, (as noted), number from the list to form the new list
  4. (Expanding the loop a few more times...)
    • Note then return the third number from the list (which is 7).
    • Discard every 7th, (as noted), number from the list to form the new list
    • Note then return the 4th number from the list (which is 9).
    • Discard every 9th, (as noted), number from the list to form the new list
    • Take the 5th, i.e. 13. Remove every 13th.
    • Take the 6th, i.e. 15. Remove every 15th.
    • Take the 7th, i.e. 21. Remove every 21th.
    • Take the 8th, i.e. 25. Remove every 25th.
  5. (Rule for the loop)
    • Note the th, which is .
    • Remove every th.
    • Increment .
Definition of even lucky numbers

This follows the same rules as the definition of lucky numbers above except for the very first step:

  1. Form a list of all the positive even integers > 0
  2. Return the first number from the list (which is 2).
  3. (Loop begins here)
    • Note then return the second number from the list (which is 4).
    • Discard every 4th, (as noted), number from the list to form the new list
  4. (Expanding the loop a few more times...)
    • Note then return the third number from the list (which is 6).
    • Discard every 6th, (as noted), number from the list to form the new list
    • Take the 4th, i.e. 10. Remove every 10th.
    • Take the 5th, i.e. 12. Remove every 12th.
  5. (Rule for the loop)
    • Note the th, which is .
    • Remove every th.
    • Increment .
Task requirements
  • Write one or two subroutines (functions) to generate lucky numbers and even lucky numbers
  • Write a command-line interface to allow selection of which kind of numbers and which number(s). Since input is from the command line, tests should be made for the common errors:
    • missing arguments
    • too many arguments
    • number (or numbers) aren't legal
    • misspelled argument (lucky or evenLucky)
  • The command line handling should:
    • support mixed case handling of the (non-numeric) arguments
    • support printing a particular number
    • support printing a range of numbers by their index
    • support printing a range of numbers by their values
  • The resulting list of numbers should be printed on a single line.


The program should support the arguments:

                             what is displayed  (on a single line)
       argument(s)              (optional verbiage is encouraged)
  ╔═══════════════════╦════════════════════════════════════════════════════╗
  ║  j                ║  Jth       lucky number                            ║
  ║  j  ,      lucky  ║  Jth       lucky number                            ║
  ║  j  ,  evenLucky  ║  Jth  even lucky number                            ║
  ║                   ║                                                    ║
  ║  j  k             ║  Jth  through  Kth (inclusive)       lucky numbers ║
  ║  j  k      lucky  ║  Jth  through  Kth (inclusive)       lucky numbers ║
  ║  j  k  evenLucky  ║  Jth  through  Kth (inclusive)  even lucky numbers ║
  ║                   ║                                                    ║
  ║  j -k             ║  all       lucky numbers in the range  j ──► |k|   ║
  ║  j -k      lucky  ║  all       lucky numbers in the range  j ──► |k|   ║
  ║  j -k  evenLucky  ║  all  even lucky numbers in the range  j ──► |k|   ║
  ╚═══════════════════╩════════════════════════════════════════════════════╝
                           where    |k|    is the absolute value of   k

Demonstrate the program by:

  • showing the first twenty lucky numbers
  • showing the first twenty even lucky numbers
  • showing all lucky numbers between 6,000 and 6,100 (inclusive)
  • showing all even lucky numbers in the same range as above
  • showing the 10,000th lucky number (extra credit)
  • showing the 10,000th even lucky number (extra credit)
See also

Haskell

Haskell is a very nice language for this problem because it is a lazy language. Here regular expressions and data types are used.

<lang Haskell> import System.Environment import System.Exit import Data.Char import Text.Regex.Posix

data Lucky = Lucky | EvenLucky

helpMessage :: IO () helpMessage = do

 putStrLn "                           what is displayed  (on a single line)"
 putStrLn "     argument(s)              (optional verbiage is encouraged)"
 putStrLn "======================|==================================================="
 putStrLn " j                    | Jth       lucky number                            "
 putStrLn " j  ,          lucky  | Jth       lucky number                            "
 putStrLn " j  ,      evenLucky  | Jth  even lucky number                            "
 putStrLn "                                                                          "
 putStrLn " j  k                 | Jth  through  Kth (inclusive)       lucky numbers "
 putStrLn " j  k          lucky  | Jth  through  Kth (inclusive)       lucky numbers "
 putStrLn " j  k      evenlucky  | Jth  through  Kth (inclusive)  even lucky numbers "
 putStrLn "                                                                          "
 putStrLn " j -k                 | all       lucky numbers in the range  j -> |k|    "
 putStrLn " j -k          lucky  | all       lucky numbers in the range  j -> |k|    "
 putStrLn " j -k      evenlucky  | all  even lucky numbers in the range  j -> |k|    "
 putStrLn "======================|==================================================="

oddNumbers :: [Int] oddNumbers = filter odd [1..]

evenNumbers :: [Int] evenNumbers = filter even [1..]

luckyNumbers :: [Int] -> [Int] luckyNumbers xs =

 let i = 3 in
 sieve i xs
   where
     sieve i (ln:s:xs) =
       ln : sieve (i + 1) (s : [x | (n, x) <- zip [i..] xs, rem n s /= 0])

nth :: Int -> Lucky -> Int nth j l = case l of

 Lucky     -> luckyNumbers oddNumbers !! (j-1)
 EvenLucky -> luckyNumbers evenNumbers !! (j-1)

range :: Int -> Int -> Lucky -> [Int] range x x2 l = case l of

   Lucky     -> drop (x-1) (take x2 (luckyNumbers oddNumbers))
   EvenLucky -> drop (x-1) (take x2 (luckyNumbers evenNumbers))

interval :: Int -> Int -> Lucky -> [Int] interval x x2 l = let x = -x2 in

 case l of
   Lucky     -> dropWhile (<x) (takeWhile (<=x) (luckyNumbers oddNumbers))
   EvenLucky -> dropWhile (<x) (takeWhile (<=x) (luckyNumbers evenNumbers))

lucky :: [String] -> Lucky lucky xs =

 if "evenLucky" `elem` xs
  then EvenLucky
  else Lucky

readn :: String -> Int readn s = read s :: Int

isInt :: String -> Bool isInt s = not (null (s =~ "-?[0-9]{0,10}" :: String))

main :: IO () main = do

 args <- getArgs
 if head args == "--help" || null args
   then
     helpMessage
   else
     let numArgs = map readn (filter isInt args) in
       if null numArgs
         then do
           print "Invalid input, missing arguments"
           print "Type --help"
           exitSuccess
         else 
           let l = lucky args in case length numArgs of
             1 -> do
               print (nth (head numArgs) l)
               exitSuccess
             2 -> if last numArgs > 0
               then do
                 print (range (head numArgs) (last numArgs) l)
                 exitSuccess
               else do
                 print (interval (head numArgs) (last numArgs) l)
                 exitSuccess
             _ -> do 
               print "Invalid input, wrong number of arguments"
               print "Type --help"
               exitSuccess</lang>
Output:
$ luckyNumbers 1 20
[1,3,7,9,13,15,21,25,31,33,37,43,49,51,63,67,69,73,75,79]
$ luckyNumbers 1 20 evenLucky
[2,4,6,10,12,18,20,22,26,34,36,42,44,50,52,54,58,68,70,76]
$ luckyNumbers 6000 -6100 lucky
[6009,6019,6031,6049,6055,6061,6079,6093]
$ luckyNumbers 6000 -6100 evenLucky
[6018,6020,6022,6026,6036,6038,6050,6058,6074,6090,6092]
$ luckyNumbers 10000
115591
$ luckyNumbers 10000 evenLucky
111842

J

Not going for extra credit because I want to encourage functional reactive "types" in J. (Note that FRP, along with an ML typed compiler, would probably remove the motivation for the while loop in this implementation.)

Implementation:

<lang J>luckySeq=:3 :0

 1 luckySeq y
 len=.0
 nth=.0
 seq=.x+2*i.4*y
 while.  len~:#seq do.
   len=. #seq
   nth=. nth+1
   seq=. nth exclude seq
 end.

)

exclude=: ] #~ 1 - #@] $ -@{ {. 1:

lucky=: evenLucky=:0 program=:3 :0

 range=: |y-.0
 seq=. (1+0 e.y) luckySeq >./range
 if. 0><./y do.
   (#~ e.&(thru/range)) seq
 else.
   (<:thru/range) { seq
 end.

)

thru=: <./ + i.@(+*)@-~</lang>

Task:

<lang J> program 1 20 1 3 7 9 13 15 21 25 31 33 37 43 49 51 63 67 69 73 75 79

  program 1 20,evenLucky

2 4 6 10 12 18 20 22 26 34 36 42 44 50 52 54 58 68 70 76

  program 6000,-6100

6009 6019 6031 6049 6055 6061 6079 6093

  program 6000,-6100,evenLucky

6018 6020 6022 6026 6036 6038 6050 6058 6074 6090 6092</lang>

Note that I've used the J command line rather than a unix or windows command line. This is because J is portable to a wide variety of environments (including phones) and there's no reliably common command line that exists across all these environments. Therefore, J must provide its own, and J's command line requires some slight syntax changes from the suggestions implicit in this task.

Perl 6

<lang perl6>sub luck(\a,\b) {

   gather {

my @taken = take a; my @rotor; my $i = b;

loop { loop (my $j = 0; $j < @rotor; $j++) { --@rotor[$j] or last; } if $j < @rotor { @rotor[$j] = @taken[$j+1]; } else { push @taken, take $i; push @rotor, $i - @taken; } $i += 2; }

   }

}

constant @lucky = luck(1,3); constant @evenlucky = luck(2,4);

subset Luck where m:i/^ 'even'? 'lucky' $/;

multi MAIN (Int $num where * > 0) {

   say @lucky[$num-1];

}

multi MAIN (Int $num where * > 0, ',', Luck $howlucky = 'lucky') {

   say @::(lc $howlucky)[$num-1];

}

multi MAIN (Int $first where * > 0, Int $last where * > 0, Luck $howlucky = 'lucky') {

   say @::(lc $howlucky)[$first-1 .. $last - 1];

}

multi MAIN (Int $min where * > 0, Int $neg-max where * < 0, Luck $howlucky = 'lucky') {

   say grep * >= $min, (@::(lc $howlucky) ...^ * > abs $neg-max);

}</lang>

Output:
$ ./lucky
Usage:
  ./lucky <num>
  ./lucky <num> , [<howlucky>] 
  ./lucky <first> <last> [<howlucky>] 
  ./lucky <min> <neg-max> [<howlucky>]
$ ./lucky 20 , lucky
79
$ ./lucky 20 , evenlucky
76
$ ./lucky 1 20
1 3 7 9 13 15 21 25 31 33 37 43 49 51 63 67 69 73 75 79
$ ./lucky 1 20 evenlucky
2 4 6 10 12 18 20 22 26 34 36 42 44 50 52 54 58 68 70 76
$ ./lucky 6000 -6100
6009 6019 6031 6049 6055 6061 6079 6093
$ ./lucky 6000 -6100 evenLucky
6018 6020 6022 6026 6036 6038 6050 6058 6074 6090 6092
$ ./lucky 10000
115591
$ ./lucky 10000 EVENLUCKY
111842

Python

The generator <lang python>from __future__ import print_function

def lgen(even=False, nmax=1000000):

   start = 2 if even else 1
   n, lst = 1, list(range(start, nmax + 1, 2))
   lenlst = len(lst)
   yield lst[0]
   while n < lenlst and lst[n] < lenlst:
       yield lst[n]
       n, lst = n + 1, [j for i,j in enumerate(lst, 1) if i % lst[n]]
       lenlst = len(lst)
   # drain
   for i in lst[n:]:
       yield i</lang>

The argument handler <lang python>from itertools import islice import sys, re

class ArgumentError(Exception):

   pass

def arghandler(argstring):

   match_obj = re.match( r"""(?mx)
   (?:
     (?P<SINGLE>
        (?: ^ (?P<SINGLEL> \d+ ) (?:  | \s , \s lucky ) \s* $ )
       |(?: ^ (?P<SINGLEE> \d+ ) (?:  | \s , \s evenLucky ) \s* $ )
     )
    |(?P<KTH>
        (?: ^ (?P<KTHL> \d+ \s \d+ ) (?:  | \s lucky ) \s* $ )
       |(?: ^ (?P<KTHE> \d+ \s \d+ ) (?:  | \s evenLucky ) \s* $ )
     )
    |(?P<RANGE>
        (?: ^ (?P<RANGEL> \d+ \s -\d+ ) (?:  | \s lucky ) \s* $ )
       |(?: ^ (?P<RANGEE> \d+ \s -\d+ ) (?:  | \s evenLucky ) \s* $ )
     )
   )""", argstring)
   
   if match_obj:
       # Retrieve group(s) by name
       SINGLEL = match_obj.group('SINGLEL')
       SINGLEE = match_obj.group('SINGLEE')
       KTHL = match_obj.group('KTHL')
       KTHE = match_obj.group('KTHE')
       RANGEL = match_obj.group('RANGEL')
       RANGEE = match_obj.group('RANGEE')
       if SINGLEL: 
           j = int(SINGLEL)
           assert 0 < j < 10001, "Argument out of range"
           print("Single %i'th lucky number:" % j, end=' ')
           print( list(islice(lgen(), j-1, j))[0] )
       elif SINGLEE: 
           j = int(SINGLEE)
           assert 0 < j < 10001, "Argument out of range"
           print("Single %i'th even lucky number:" % j, end=' ')
           print( list(islice(lgen(even=True), j-1, j))[0] )
       elif KTHL: 
           j, k = [int(num) for num in KTHL.split()]
           assert 0 < j < 10001, "first argument out of range"
           assert 0 < k < 10001 and k > j, "second argument out of range"
           print("List of %i ... %i lucky numbers:" % (j, k), end=' ')
           for n, luck in enumerate(lgen(), 1):
               if n > k: break
               if n >=j: print(luck, end = ', ')
           print()
       elif KTHE: 
           j, k = [int(num) for num in KTHE.split()]
           assert 0 < j < 10001, "first argument out of range"
           assert 0 < k < 10001 and k > j, "second argument out of range"
           print("List of %i ... %i even lucky numbers:" % (j, k), end=' ')
           for n, luck in enumerate(lgen(even=True), 1):
               if n > k: break
               if n >=j: print(luck, end = ', ')
           print()
       elif RANGEL: 
           j, k = [int(num) for num in RANGEL.split()]
           assert 0 < j < 10001, "first argument out of range"
           assert 0 < -k < 10001 and -k > j, "second argument out of range"
           k = -k
           print("List of lucky numbers in the range %i ... %i :" % (j, k), end=' ')
           for n in lgen():
               if n > k: break
               if n >=j: print(n, end = ', ')
           print()
       elif RANGEE: 
           j, k = [int(num) for num in RANGEE.split()]
           assert 0 < j < 10001, "first argument out of range"
           assert 0 < -k < 10001 and -k > j, "second argument out of range"
           k = -k
           print("List of even lucky numbers in the range %i ... %i :" % (j, k), end=' ')
           for n in lgen(even=True):
               if n > k: break
               if n >=j: print(n, end = ', ')
           print()
   else:
       raise ArgumentError(
       
 Error Parsing Arguments!
 
 Expected Arguments of the form (where j and k are integers):
     
     j                #  Jth       lucky number
     j  ,      lucky  #  Jth       lucky number
     j  ,  evenLucky  #  Jth  even lucky number
                      #
     j  k             #  Jth  through  Kth (inclusive)       lucky numbers
     j  k      lucky  #  Jth  through  Kth (inclusive)       lucky numbers
     j  k  evenLucky  #  Jth  through  Kth (inclusive)  even lucky numbers
                      #
     j -k             #  all       lucky numbers in the range  j --? |k|
     j -k      lucky  #  all       lucky numbers in the range  j --? |k|
     j -k  evenLucky  #  all  even lucky numbers in the range  j --? |k|
       )

if __name__ == '__main__':

   arghandler(' '.join(sys.argv[1:]))</lang>
Output:
# Output when arguments are: 1 20 lucky
List of 1 ... 20 lucky numbers: 1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 49, 51, 63, 67, 69, 73, 75, 79, 
# Output when arguments are: 1 20 evenLucky
List of 1 ... 20 even lucky numbers: 2, 4, 6, 10, 12, 18, 20, 22, 26, 34, 36, 42, 44, 50, 52, 54, 58, 68, 70, 76, 
# Output when arguments are: 6000 -6100 lucky
List of lucky numbers in the range 6000 ... 6100 : 6009, 6019, 6031, 6049, 6055, 6061, 6079, 6093, 
# Output when arguments are: 6000 -6100 evenLucky
List of even lucky numbers in the range 6000 ... 6100 : 6018, 6020, 6022, 6026, 6036, 6038, 6050, 6058, 6074, 6090, 6092, 
# Output when arguments are: 10000
Single 10000'th lucky number: 115591
# Output when arguments are: 10000 , evenLucky
Single 10000'th even lucky number: 111842

REXX

This REXX version does extra error checking for the arguments. <lang REXX>/*REXX program displays lucky or evenLucky integers (numbers or a number range).*/ parse arg bot top func _ . /*obtain required & optional arguments.*/ if func== then func='lucky' /*Not specified? Then use the default.*/ s=left('s', bot\==top & top\==",") /*plural results (or maybe not plural).*/ say func 'number's":" bot top '───►' $lucky(bot, top, func, _) exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ $lucky: arg x,y,f,?; if y== | y=="," then y=x /*obtain some arguments; set Y.*/

       #=0;        $=;      ny=y<0                      /*set variable NOY: value range*/
       if f==  then f='LUCKY';  lucky= (f=="LUCKY")   /*assume  LUCKY  if omitted.   */
       if f\=='LUCKY' & f\=='EVENLUCKY'  then return  'function not valid: '     f
       if arg()>3  &  ?\=      then return  "too many arguments entered: "     ?
       if x=                   then return  "1st argument is missing."
       if x<1                    then return  "1st argument isn't a positive integer: " x
       if \datatype(x,'W')       then return  "1st argument isn't an integer: "  x
       if \datatype(y,'W')       then return  "2nd argument isn't an integer: "  y
       if x>ay                   then return  "2nd argument is less than 1st arg."
       ay=abs(y); yL=ay; if y>0  then yL=y*10+y+y       /*adjust the upper  Y  limit.  */
                                                        /* [↓]  build LUCKY | EVENLUCKY*/
           do j=1  until j>=yL                          /*construct list pos. integers.*/
           if j//2==(\lucky)  then iterate              /*EVENLUCKY? Use only even ints*/
           if lucky  then if (j+1)//6==0  then iterate  /*prune       if  mod 6 ≡ zero.*/
                                          else nop      /*balance the   IF-THEN  logic.*/
                     else if  j   //8==0  then iterate  /*prune next  if  mod 8 ≡ zero.*/
           #=#+1                                        /*bump the counter of numbers. */
           $=$ j                                        /*append integer to the $ list.*/
           end   /*j*/
       q=0
           do p=3  until  q==;     q=word($,p)        /*start to prune  integer list.*/
           if q>#  then leave                           /*if integer is too large, stop*/
                              do j=#%q*q  by -q  to q   /*elide every  Qth  integer.   */
                              $=delword($, j, 1)        /*delete a particular number.  */
                              #=#-1                     /*decrease the integer count.  */
                              end   /*j*/               /*delete from the right side.  */
           end   /*p*/
       @.=
                 do k=1; parse var $ q $;  if q==  then leave;  @.k=q;  end  /*k*/
       @.0=k-1
                 do m=1  for #                          /*restrict the found integers. */
                 if (\ny  &  (m<x  |  m>ay))  |  (ny  &  (@.m<x | @.m>ay))  then @.m=
                 end   /*m*/                            /* [↑]  a list of #s or a range*/
       _=
                 do b=1  for @.0; _=_ @.b; end  /*b*/   /*construct a list of integers.*/
       return space(_)                                  /*remove superfluous blanks.   */</lang>

output   when the input is:   1   20   lucky

lucky numbers: 1 20 ───► 1 3 7 9 13 15 21 25 31 33 37 43 49 51 63 67 69 73 75 79

output   when the input is:   1   20   evenLucky

evenLucky numbers: 1 20 ───► 2 4 6 10 12 18 20 22 26 34 36 42 44 50 52 54 58 68 70 76

output   when the input is:   6000   -6100   lucky

lucky numbers: 6000 -6100 ───► 6009 6019 6031 6049 6055 6061 6079 6093

output   when the input is:   6000   -6100   venLucky

evenLucky numbers: 6000 -6100 ───► 6018 6020 6022 6026 6036 6038 6050 6058 6074 6090 6092

output   when the input is:   10000

lucky number: 10000 ───► 115591

output   when the input is:   10000   ,   evenLucky

evenLucky number: 10000 ───► 111842

Ruby

Translation of: Python

<lang ruby>def generator(even=false, nmax=1000000)

 start = even ? 2 : 1
 Enumerator.new do |y|
   n = 1
   ary = [0] + (start..nmax).step(2).to_a      # adds [0] to revise the 0 beginnings.
   y << ary[n]
   while (m = ary[n+=1]) < ary.size
     y << m
     (m...ary.size).step(m){|i| ary[i]=nil}
     ary.compact!                              # remove nil
   end
   # drain
   ary[n..-1].each{|i| y << i}
   raise StopIteration
 end

end

def lucky(argv)

 j, k = argv[0].to_i, argv[1].to_i
 mode = /even/i=~argv[2] ? :'even lucky' : :lucky
 seq = generator(mode == :'even lucky')
 ord = ->(n){"#{n}#{(n%100).between?(11,19) ? 'th' : %w[th st nd rd th th th th th th][n%10]}"}
 if k.zero?
   puts "#{ord[j]} #{mode} number: #{seq.take(j).last}"
 elsif 0 < k
   puts "#{ord[j]} through #{ord[k]} (inclusive) #{mode} numbers",
        "  #{seq.take(k)[j-1..-1]}"
 else
   k = -k
   ary = []
   loop do
     case num=seq.next
     when 1...j
     when j..k  then ary << num
     else break
     end
   end
   puts "all #{mode} numbers in the range #{j}..#{k}",
        "  #{ary}"
 end

end

if __FILE__ == $0

 lucky(ARGV)

end</lang>

Output:
C:\>ruby lucky.rb 1 20
1st through 20th (inclusive) lucky numbers
  [1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 49, 51, 63, 67, 69, 73, 75, 79]

C:\>ruby lucky.rb 1 20 evenLucky
1st through 20th (inclusive) even lucky numbers
  [2, 4, 6, 10, 12, 18, 20, 22, 26, 34, 36, 42, 44, 50, 52, 54, 58, 68, 70, 76]

C:\>ruby lucky.rb 6000 -6100 Lucky
all lucky numbers in the range 6000..6100
  [6009, 6019, 6031, 6049, 6055, 6061, 6079, 6093]

C:\>ruby lucky.rb 6000 -6100 evenLucky
all even lucky numbers in the range 6000..6100
  [6018, 6020, 6022, 6026, 6036, 6038, 6050, 6058, 6074, 6090, 6092]

C:\>ruby lucky.rb 10000
10000th lucky number: 115591

C:\>ruby lucky.rb 10000 , EVENLUCKY
10000th even lucky number: 111842

Tcl

Works with: Tcl version 8.6
Translation of: Python

<lang tcl>#!/usr/bin/env tclsh8.6 package require Tcl 8.6

proc lgen {{even false} {nmax 200000}} {

   coroutine lgen.[incr ::lgen] apply {{start nmax} {

set n 1 for {set i $start} {$i <= $nmax+1} {incr i 2} {lappend lst $i} yield [info coroutine] yield [lindex $lst 0] while {$n < [llength $lst] && [lindex $lst $n] < [llength $lst]} { yield [lindex $lst $n] set lst [set i 0;lmap j $lst { if {[incr i] % [lindex $lst $n]} {set j} else continue }] incr n } foreach i [lrange $lst $n end] { yield $i }

   }} [expr {$even ? 2 : 1}] $nmax

}

proc collectIndices {generator from to} {

   set result {}
   for {set i 0} {$i <= $to} {incr i} {

set n [$generator] if {$i >= $from} {lappend result $n}

   }
   rename $generator {}
   return $result

} proc collectValues {generator from to} {

   set result {}
   while 1 {

set n [$generator] if {$n > $to} break if {$n >= $from} {lappend result $n}

   }
   rename $generator {}
   return $result

}

if {$argc<1||$argc>3} {

   puts stderr "wrong # args: should be \"$argv0 from ?to? ?evenOdd?\""
   exit 1

} lassign $argv from to evenOdd if {$argc < 3} {set evenOdd lucky} if {$argc < 2} {set to ,} if {![string is integer -strict $from] || $from < 1} {

   puts stderr "\"from\" must be positive integer"
   exit 1

} elseif {$to ne "," && (![string is integer -strict $to] || $to == 0)} {

   puts stderr "\"to\" must be positive integer or comma"
   exit 1

} elseif {[set evenOdd [string tolower $evenOdd]] ni {lucky evenlucky}} {

   puts stderr "\"evenOdd\" must be \"lucky\" or \"evenLucky\""
   exit 1

} set l [lgen [expr {$evenOdd eq "evenlucky"}]] set evenOdd [lindex {"lucky" "even lucky"} [expr {$evenOdd eq "evenlucky"}]] if {$to eq ","} {

   puts "$from'th $evenOdd number = [collectIndices $l [incr from -1] $from]"

} elseif {$to < 0} {

   set to [expr {-$to}]
   puts "all $evenOdd numbers from $from to $to: [join [collectValues $l $from $to] ,]"

} else {

   puts "$from'th to $to'th $evenOdd numbers: [join [collectIndices $l [incr from -1] [incr to -1]] ,]"

}</lang>

Output:
bash$ lucky.tcl 1 20
1'th to 20'th lucky numbers: 1,3,7,9,13,15,21,25,31,33,37,43,49,51,63,67,69,73,75,79
bash$ lucky.tcl 1 20 evenLucky
1'th to 20'th even lucky numbers: 2,4,6,10,12,18,20,22,26,34,36,42,44,50,52,54,58,68,70,76
bash$ lucky.tcl 6000 -6100
all lucky numbers from 6000 to 6100: 6009,6019,6031,6049,6055,6061,6079,6093
bash$ lucky.tcl 6000 -6100 evenLucky
all even lucky numbers from 6000 to 6100: 6018,6020,6022,6026,6036,6038,6050,6058,6074,6090,6092
bash$ lucky.tcl 10000
10000'th lucky number = 115591
bash$ lucky.tcl 10000 , evenLucky
10000'th even lucky number = 111842

zkl

The lucky number generator works by chaining filters to a even or odd infinite sequence. So it acts like a sieve as each starting number percolates through the filters. It also means there are lots and lots of filters, which doesn't scale well but works for the examples. <lang zkl>fcn lgen(a){

  ns,idx:=[a..*,2],2;
  vm.yield(ns.next());
  while(1){
     n:=ns.next();
     vm.yield(n);
     ns=ns.tweak(skipper.fp1(n,Ref(idx+=1)));  // tack on another filter
  }

} fcn skipper(n,skp,cnt){ z:=cnt.inc(); if(z%skp==0) Void.Skip else n }</lang> The command line is a bit funky (by Unix standards) so we just hard code it and use exceptions (such as trying to convert "foo" to int) to show the options. <lang zkl>cmdLineArgs,j,k,start:=vm.arglist,Void,Void,1; try{

  j=cmdLineArgs[0].toInt();
  na:=cmdLineArgs.len();
  if(na>1){
     if(cmdLineArgs[1]==",")
        start=cmdLineArgs[2][0].toLower()=="e" and 2 or 1;
     else{

k=cmdLineArgs[1].toInt(); if(na>2) start=cmdLineArgs[2][0].toLower()=="e" and 2 or 1;

     }
  }

}catch{

  fcn options{
     "args: j | j , [even]lucky | j k [even]lucky | j -k [even]lucky"
     .println(); 
     System.exit(1); 
  }()

} luckies:=Utils.Generator(lgen,start); try{

  if(Void==k) luckies.drop(j-1).next().println();
  else{
     if(k>0) luckies.drop(j-1).walk(k-j+1).println();
     else{ k=-k;

while((n:=luckies.next())<j){} luckies.push(n); luckies.pump(List,'wrap(n){ n<=k and n or Void.Stop }).println();

     }
  }

}catch(TheEnd){ options() }</lang>

Output:
$ zkl lucky
args: j | j , [even]lucky | j k [even]lucky | j -k [even]lucky
$ zkl lucky 1 20
L(1,3,7,9,13,15,21,25,31,33,37,43,49,51,63,67,69,73,75,79)
$ zkl lucky 1 20 evenLucky
L(2,4,6,10,12,18,20,22,26,34,36,42,44,50,52,54,58,68,70,76)
$ zkl lucky 6000 -6100
L(6009,6019,6031,6049,6055,6061,6079,6093)
$ zkl lucky 6000 -6100 Even
L(6018,6020,6022,6026,6036,6038,6050,6058,6074,6090,6092)
$ zkl lucky 10000
115591
$ zkl lucky 10000 , evenLucky
111842
$ zkl lucky 6000 -5000
L()
$ zkl lucky 4 2
args: j | j , [even]lucky | j k [even]lucky | j -k [even]lucky