7
\$\begingroup\$

(Continuing on the number sequences code-golf, here is an interesting sequence)

Eban Numbers (A006933) are the sequence of numbers whose names (in English) do not contain the letter "e" (i.e., "e" is "banned")

The first few numbers in the sequence are:

2, 4, 6, 30, 32, 34, 36, 40, 42, 44, 46, 50, 52, 54, 56

Given an integer n, via function argument or STDIN, return the first n terms of the Eban Numbers (in numbers) .

Since some answers will involve some sort of string check for character e, assume that the maximum value of n can be such that the nth Eban number is less than 1 Quadrillion.

\$\endgroup\$
  • \$\begingroup\$ related: codegolf.stackexchange.com/questions/36512/… \$\endgroup\$ – Howard Sep 12 '14 at 13:34
  • \$\begingroup\$ Searching questions on this site is pretty primitive ... Anyways, Eban numbers are more tricky than Iban in so many ways :) \$\endgroup\$ – Optimizer Sep 12 '14 at 13:38
  • \$\begingroup\$ Do the terms have to be output numerically, or may they be output as words? \$\endgroup\$ – Digital Trauma Sep 12 '14 at 20:08
  • \$\begingroup\$ Yes, numeric output. \$\endgroup\$ – Optimizer Sep 12 '14 at 20:13
  • \$\begingroup\$ Are we allowed to use modules off CPAN that aren't in the core if doing a Perl solution? \$\endgroup\$ – chilemagic Sep 12 '14 at 21:24
6
\$\begingroup\$

Mathematica CJam, 108 95 46 35 30 bytes

Edit: Ported to CJam! The original and ungolfed Mathematica code is at the bottom and explains the algorithm quite well.

li,{)Kb65430s2046sm*$f=0s*ip}/

And now I know CJam. :D Thanks to Dennis for some golfing improvements.

After analysing them a bit to determine how many there are below one quadrillion, I came to the conclusion that all eban numbers are basically base-1000 numbers using only a set of 20 digits:

0, 2, 4, 6, 30, 32, 34, 36, 40, 42, 44, 46, 50, 52, 54, 56, 60, 62, 64, 66

So we enumerate them by converting the input to base 20, picking the right digit from the set and build a base 1000 number from it.

This is how the code works in detail:

li                             "Read from STDIN, convert to integer n";
li,                            "Turn into a range array [0 ... n-1]";
li,{                        }/ "For each number execute a block";
li,{)                       }/ "Increment";
li,{)K                      }/ "K is initialised to 20, push that";
li,{)Kb                     }/ "Convert to base 20";
li,{)Kb65430s               }/ "Push a string with possible multiples of 10";
li,{)Kb65430s2046s          }/ "Push a string with possible least significant digits";
li,{)Kb65430s2046sm*        }/ "Take the Cartesian product of the two character
                                arrays, generating the 20 'digits'";
li,{)Kb65430s2046sm*$       }/ "Sort the result";
li,{)Kb65430s2046sm*$f=     }/ "For each digit in our base-20 number, get the
                                base-1000 digit from the list";
li,{)Kb65430s2046sm*$f=0s   }/ "Push a '0' character";
li,{)Kb65430s2046sm*$f=0s*  }/ "Join all the digits, with that '0' as the delimiter";
li,{)Kb65430s2046sm*$f=0s*ip}/ "Convert to an integer and print the result";

Here was the original Mathematica code, which doesn't encode the digit list and is hence fairly readable:

{0,2,4,6,30,32,34,36,40,42,44,46,50,52,54,56,60,62,64,66}[[IntegerDigits[#,20]+1]]~FromDigits~1000 & /@ Range @ # &
\$\endgroup\$
  • 1
    \$\begingroup\$ Unprintable characters would work just fine. You can replace 20 with K, 1000 with 1e3, {i41-}% with 41f- and {")+-/GIKMQSUW[]_aegik"41f-=}% with ")+-/GIKMQSUW[]_aegik"41f-f=. Futhermore, the array (string) could be pushed as [4U5Z6][U4Y6]m*Afb$ (m* is Cartesian product, $ is sort), for a total of 33 bytes (35 if you prepend li to read from STDIN). \$\endgroup\$ – Dennis Sep 13 '14 at 6:39
  • \$\begingroup\$ @Dennis I knew I was missing out on a lot of good tricks, thanks! ;) I just remembered that CJam happily deals with large bases so I quickly wanted to throw something together, because I figured this could beat all other answers. I'll go through your tips and work them in when I understand why they work. :) \$\endgroup\$ – Martin Ender Sep 13 '14 at 8:11
  • \$\begingroup\$ You can save 5 more bytes by using strings instead of numbers, eliminating the need for the last two base conversions: li,{)Kb65430s2046sm*$f=0s*ip}/. Unfortunately, 'ヨis'०is has the same byte count as 65430s2046s. \$\endgroup\$ – Dennis Sep 13 '14 at 12:56
  • \$\begingroup\$ @Dennis Interesting. What's the difference between / and %? \$\endgroup\$ – Martin Ender Sep 13 '14 at 13:11
  • \$\begingroup\$ Doesn't really matter here, just force of habit. % collects the results in an array, so it leaves an empty array on the stack here. Since those aren't printed, it would only matter for a function. \$\endgroup\$ – Dennis Sep 13 '14 at 13:19
4
\$\begingroup\$

Bash+coreutils+BSDGames package, 79 70 bytes

seq $[9**16]|while read n
do number $n|grep -q e||echo $n
done|sed $1q

Unfortunately this spawns number $n|grep -q e for every number, so is rather slow.

Output:

$ ./eban.sh 5
2
4
6
30
32
$ 

Previous answer - outputs words instead of digits, 43 bytes

seq $[9**16]|number -l|grep -v [e.]|sed $1q

This outputs each term written in words:

$ ./eban.sh 5
two
four
six
thirty
thirty-two
$ 

A bit faster, because each process is only spawned once.


Much faster, no dependence on cheaty number, 77 bytes

t=0{0,3,4,5,6}{0,2,4,6}
eval echo $t$t$t$t$t|tr \  '
'|sed "s/^0*//;$[$1+1]q"

This one uses bash brace expansion to generate all (according to my thinking) eban numbers up to 10^15. Looking at each group of 3 digits, the units digit must be one of {zero,two,four,six}, the tens digit must be one of {zero,thirty,forty,fifty,sixty}, and the hundreds digit must be zero. Since x-illion contains no e's up to quadrillion, then we can just combine the groups of three digits up to one quadrillion. The only exception is zero which must be skipped.

So we simply build a brace expansion to generate all these numbers. There are thus 205-1 of them (3.2 million). Evaluating the full bash brace expansion takes less than 5 seconds on my VM.

The sed expression just strips off leading zeros and counts to n.

Output:

$ time ./eban.bash 5

2
4
6
30
32

real    0m4.065s
user    0m3.724s
sys 0m0.276s
$ ./eban.bash 10000000 | wc -w
3199999
$ ./eban.bash 3199999 | tail -5
66066066066056
66066066066060
66066066066062
66066066066064
66066066066066
$ 
\$\endgroup\$
  • \$\begingroup\$ Will this first generate 10^15 numbers and then stop at $1 ? or incrementally check and stop generating after 5th number ? \$\endgroup\$ – Optimizer Sep 12 '14 at 20:01
  • \$\begingroup\$ @Optimizer seq can generate that many numbers, but because this is all a long pipeline, whenever any one of the processes quits, the shell will send a SIGPIPE to all processes in the pipeline, and thus they will all quit. In this case, the sed $1q will quit after the nth line it receives, and thus the rest of the pipline will be torn down, before seq can count much further (modulo buffering in each pipe). \$\endgroup\$ – Digital Trauma Sep 12 '14 at 20:04
  • \$\begingroup\$ I think you can probably play around and print the actual number instead of the English version. Maybe via awk/sed. \$\endgroup\$ – Optimizer Sep 12 '14 at 20:10
  • 1
    \$\begingroup\$ please do it... \$\endgroup\$ – Optimizer Sep 12 '14 at 20:13
  • 1
    \$\begingroup\$ @Optimizer Looks like that old bash version has poor memory management. If you're serious about testing the more Linuxey answers, I recommend you install some distro (Ubuntu is easy) in a VM. Virtualbox and VMWare player are free, I think. Another thing you can try for this answer is replace $t$t$t$t$t with $t$t$t$t. With this the script will work with numbers up to 1 trillion. \$\endgroup\$ – Digital Trauma Sep 12 '14 at 23:42
2
\$\begingroup\$

Ruby, 128 121 119 bytes

f=->n{a=[]
i=0
(j=i+=2
b=p
(m=j%t=1000
b=b||m%2>0||m%10==8||m>9&&m<30||m>69
j/=t)while j>0
a<<i if !b)while a.size<n
a}

I'm basically just checking groups of three digits for numbers that contain es, because none of {thousand, million, billion, trillion, quadrillion} contains an e.

\$\endgroup\$
  • \$\begingroup\$ You can safely do i+=2 as all numbers in Eban numbers are even \$\endgroup\$ – Optimizer Sep 12 '14 at 18:32
  • \$\begingroup\$ @Optimizer lol yeah, since I have a m%2>0|| I was even aware of that. :D thanks! \$\endgroup\$ – Martin Ender Sep 12 '14 at 18:34
  • \$\begingroup\$ Can you probably find out n where it crosses a quadrillion ? I don't have the setup and online compilers won't run for that big n \$\endgroup\$ – Optimizer Sep 12 '14 at 18:47
  • \$\begingroup\$ @Optimizer Not with the program. I'd need an optimised version which skips over thousands/millions/etc if the offending "e" comes from one of the more significant digits. But if I'm not mistaken, there should be Σ(n=1...5) 19^n = 2,613,659 eban numbers below a quadrillion. \$\endgroup\$ – Martin Ender Sep 12 '14 at 19:41
  • 1
    \$\begingroup\$ @Optimizer I think I was mistaken. I think it should be 20^5-1 = 3199999 eban numbers below a quadrillion instead. \$\endgroup\$ – Martin Ender Sep 12 '14 at 22:35
1
\$\begingroup\$

Perl - 78

Here is a Perl one-liner to do it.

perl -MLingua::EN::Numbers=num2en -nE'while($n<=$_){$n++&&say$i if num2en($i)!~/e/;$i++}' <(echo 5)

It is 50 characters plus 1 for the M, 1 for the n, and 26 for Lingua::EN::Numbers=num2len.

Using Lingua::EN::Numbers from CPAN. Here are instructions for installing CPAN modules.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.