Lucky and even lucky numbers: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|REXX}}: changed/added comments and whitespace, changed indentations.)
Line 453: Line 453:


=={{header|REXX}}==
=={{header|REXX}}==
This REXX version does extra error checking for the arguments.
<lang REXX>/*REXX program displays lucky or evenLucky integers (#'s or a # range).*/
<lang REXX>/*REXX program displays lucky or evenLucky integers (numbers or a number range).*/
parse arg bot top func _ . /*get what we need from the C.L. */
if func=='' then func='lucky' /*Not defined? Use the default. */
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 not plural).*/
say func 'number's":" bot top '───►' $lucky(bot, top, func, _)
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 done.*/
exit /*stick a fork in it, we're all done. */
/*────────────────────────────────$LUCKY subroutine─────────────────────*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
$lucky: arg x,y,f,?; if y=='' | y==',' then y=x /*get some vars.*/
#=0; $=; ny=y<0 /*set variable: NOY: value range*/
$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 f=='' then f='LUCKY'; lucky= (f=="LUCKY") /*assume LUCKY if omitted. */
if arg()>3 & ?\='' then return "too many arguments entered: " ?
if f\=='LUCKY' & f\=='EVENLUCKY' then return 'function not valid: ' f
if x='' then return "1st argument is missing."
if arg()>3 & ?\='' then return "too many arguments entered: " ?
if x<1 then return "1st argument isn't a positive integer: " x
if x='' then return "1st argument is missing."
if \datatype(x,'W') then return "1st argument isn't an integer: " x
if x<1 then return "1st argument isn't a positive integer: " x
if \datatype(y,'W') then return "2nd argument isn't an integer: " y
if \datatype(x,'W') then return "1st argument isn't an integer: " x
if x>ay then return "2nd arg is less than 1st arg."
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. */
ay=abs(y); yL=ay; if y>0 then yL=y*10+y+y /*adjust the upper Y limit. */
if f=='' then f='LUCKY'; lucky=f=='LUCKY'
/* [↓] build for LUCKY|EVENLUCKY*/
/* [↓] build LUCKY | EVENLUCKY*/
do j=1 until j>=yL /*construct list of pos integers.*/
do j=1 until j>=yL /*construct list pos. integers.*/
if j//2==(\lucky) then iterate /*EVENLUCKY? Use only even ints.*/
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.*/
if lucky then if (j+1)//6==0 then iterate /*prune if mod 6 ≡ zero.*/
else nop /*balance the IF logic. */
else nop /*balance the IF-THEN logic.*/
else if j //8==0 then iterate /*prune next if mod 8≡0.*/
else if j //8==0 then iterate /*prune next if mod 8 ≡ zero.*/
#=#+1 /*bump the counter of #'s found. */
#=#+1 /*bump the counter of numbers. */
$=$ j /*append integer to the $ list.*/
$=$ j /*append integer to the $ list.*/
end /*j*/
end /*j*/
q=0
z=0
do p=3 until z==''; z=word($,p) /*start to prune the integer list*/
do p=3 until q==''; q=word($,p) /*start to prune integer list.*/
if z># then leave /*if integer is too large, stop. */
if q># then leave /*if integer is too large, stop*/
do j=#%z*z by -z to z /*elide every Zth int.*/
do j=#%q*q by -q to q /*elide every Qth integer. */
$=delword($,j,1) /*delete a particular #.*/
$=delword($, j, 1) /*delete a particular number. */
#=#-1 /*decrease integer count*/
#=#-1 /*decrease the integer count. */
end /*j*/ /*delete from right end.*/
end /*j*/ /*delete from the right side. */
end /*p*/
end /*p*/
@.=
@.=
do k=1; parse var $ q $; if q=='' then leave; @.k=q; end /*k*/
do k=1; parse var $ q $; if q=='' then leave; @.k=q; end /*k*/
@.0=k-1
@.0=k-1
do j=1 for # /*restrict the found integers. */
do m=1 for # /*restrict the found integers. */
if (\ny & (j<x | j>ay)) | (ny & (@.j<x | @.j>ay)) then @.j=
if (\ny & (m<x | m>ay)) | (ny & (@.m<x | @.m>ay)) then @.m=
end /*j*/ /* [↑] a list of #s or a range. */
end /*m*/ /* [↑] a list of #s or a range*/
_=
_=
do b=1 for @.0; _=_ @.b; end /*build a list. */
do b=1 for @.0; _=_ @.b; end /*b*/ /*construct a list of integers.*/
return space(_) /*remove superfluous list blanks.*/</lang>
return space(_) /*remove superfluous blanks. */</lang>
'''output''' when the input is: &nbsp; <tt> 1 20 lucky </tt>
'''output''' &nbsp; when the input is: &nbsp; <tt> 1 &nbsp; 20 &nbsp; lucky </tt>
<pre>
<pre>
lucky numbers: 1 20 ───► 1 3 7 9 13 15 21 25 31 33 37 43 49 51 63 67 69 73 75 79
lucky numbers: 1 20 ───► 1 3 7 9 13 15 21 25 31 33 37 43 49 51 63 67 69 73 75 79
</pre>
</pre>
'''output''' when the input is: &nbsp; <tt> 1 20 evenLucky </tt>
'''output''' &nbsp; when the input is: &nbsp; <tt> 1 &nbsp; 20 &nbsp; evenLucky </tt>
<pre>
<pre>
evenLucky numbers: 1 20 ───► 2 4 6 10 12 18 20 22 26 34 36 42 44 50 52 54 58 68 70 76
evenLucky numbers: 1 20 ───► 2 4 6 10 12 18 20 22 26 34 36 42 44 50 52 54 58 68 70 76
</pre>
</pre>
'''output''' when the input is: &nbsp; <tt> 6000 -6100 lucky</tt>
'''output''' &nbsp; when the input is: &nbsp; <tt> 6000 &nbsp; -6100 &nbsp; lucky</tt>
<pre>
<pre>
lucky numbers: 6000 -6100 ───► 6009 6019 6031 6049 6055 6061 6079 6093
lucky numbers: 6000 -6100 ───► 6009 6019 6031 6049 6055 6061 6079 6093
</pre>
</pre>
'''output''' when the input is: &nbsp; <tt> 6000 -6100 evenLucky</tt>
'''output''' &nbsp; when the input is: &nbsp; <tt> 6000 &nbsp; -6100 &nbsp; venLucky</tt>
<pre>
<pre>
evenLucky numbers: 6000 -6100 ───► 6018 6020 6022 6026 6036 6038 6050 6058 6074 6090 6092
evenLucky numbers: 6000 -6100 ───► 6018 6020 6022 6026 6036 6038 6050 6058 6074 6090 6092
</pre>
</pre>
'''output''' when the input is: &nbsp; <tt> 10000 </tt>
'''output''' &nbsp; when the input is: &nbsp; <tt> 10000 </tt>
<pre>
<pre>
lucky number: 10000 ───► 115591
lucky number: 10000 ───► 115591
</pre>
</pre>
'''output''' when the input is: &nbsp; <tt> 10000 , evenLucky </tt>
'''output''' &nbsp; when the input is: &nbsp; <tt> 10000 &nbsp; , &nbsp; evenLucky </tt>
<pre>
<pre>
evenLucky number: 10000 ───► 111842
evenLucky number: 10000 ───► 111842

Revision as of 22:07, 16 April 2016

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.

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

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