# Undulant numbers

An undulant number is a number where its digits go up and down like the following number: 461902 or 708143, or even 1010101, but not 123, because 2 < 3. write function which returns true if a number is undulant, false otherwise. The shortest function wins.

NOTE: For completeness, single digit numbers are accepted by the function and the function would return false (I imagine this case as non-undulant number), thus isUndulant returns false for n < 10.

-
Number input as string, integer, float...? – leftaroundabout Jul 11 '11 at 19:07
What's the objective here? Code-golf (shortest function)? – Alexandru Jul 11 '11 at 20:22
@JBernardo: I would think True or undefined behavior, as it would be a better base case for recursion. – Joey Adams Jul 11 '11 at 21:26
Your definition of undulant number is not in agreement with the standard definition: mathworld.wolfram.com/UndulatingNumber.html. Is this intentional? – mellamokb Jul 14 '11 at 12:03
My solution could be 16% smaller if the base case were true (as would make sense IMHO). – eternalmatt Jul 15 '11 at 23:22

## J, 45

*./(n>9),(}:(=-)}.)(}:*@-}.)n#:~10$~>.10^.n=.  Sample use:  *./(n>9),(}:(=-)}.)(}:*@-}.)n#:~10$~>.10^.n=. 461902
1
*./(n>9),(}:(=-)}.)(}:*@-}.)n#:~10$~>.10^.n=. 708143 1 *./(n>9),(}:(=-)}.)(}:*@-}.)n#:~10$~>.10^.n=. 1010101
1
*./(n>9),(}:(=-)}.)(}:*@-}.)n#:~10$~>.10^.n=. 123 0 *./(n>9),(}:(=-)}.)(}:*@-}.)n#:~10$~>.10^.n=. 5
0


I'm pretty sure there's a finer way of twisting Insert / to do more of the work in a go, but I've been J-less for months, I need to get back to it.

-
 It will be hard to beat J in this problem. nice solution! – leonardo Jul 13 '11 at 15:21 @leonardo thanks! – J B Jul 13 '11 at 16:15

### Ruby, 72 70 characters

Q=10;k=->n,v{(n%Q-n/Q%Q)*v<0?k[n/Q,-v]:n<Q};u=->n{n>9&&k[n,-1]|k[n,1]}


Usage and testcases:

p u[10101]   # <= true
p u[708143]  # <= true
p u[2421]    # <= false
p u[1231]    # <= false
p u[873]     # <= false


Single digits yield false:

p u[5]       # <= false


Consecutive identical digits also return false:

p u[66]      # <= false
p u[1221]    # <= false

-

q[]=9<3
q[e]=e/=EQ
q(a:b:s)=a/=EQ&&a/=b&&q(b:s)
w s=zipWith compare s$tail s u=q.w.show  -  I am so furious that you beat my 104 char solution. u n=length s>1&&(a[GT,LT]||a[LT,GT])where s=show n;z=q compare s$tail s;w=q(==)z;q=zipWith;a=and.w.cycle It's kinda elegant. zipWith once with compare like you did, then zipWith again with (==) and cycle[GT,LT] or cycle[LT,GT] as second arg. – eternalmatt Jul 15 '11 at 23:07

### Python: 101 100 characters

Before minification:

undulate = (lambda n: n > 9
and all(cmp(*digits) == (i % 2) * 2 - 1
for i, digits
in enumerate(zip(min(n,n[1:]),
max(n,n[1:])))))


After minification:

a=lambda b:b>9and all(cmp(*c)==d%2*2-1 for d,c in enumerate(zip(min(b,b[1:]),max(b,b[1:]))))

-

Sage, 76 83char

f=lambda x:uniq(cmp(*x[i-2:i][::(-1)^i])for i in[2..len(x)])in[[1],[-1]]


Got the idea to use cmp(*[..]) from JBernardo. In Sage, uniq(...) is an alias for list(set(...)).

Edit: just noticed that for x < 10, uniq(cmp(...)) == [], which isn't on [[1],[-1]]. If x were input as a string, instead of an integer, I could get another 4 characters out!

-
 I had an idea to use sum(uniq(...))^2, since sum([1,-1]) = 0, and the sums of the singletons [1] and [-1] squares to 1. Unfortunately, it fails on a thrice-repeated digit; 1011101. – boothby Jul 12 '11 at 16:58 Nice. I should learn sage. BTW, I just realized that backticks will append an L if the number is bigger than 2**32 in Python and affects the result. Does that happens on Sage? – JBernardo Jul 12 '11 at 20:02 Yeah, Sage makes a few things nice for golfing... for instance, its ridiculous startup time is spent importing a huge tree of modules. The Sage Integer class doesn't bother with the L because Sage is preparsed python; 1234 -> Integer('1234'). You can jump right into using Sage here: sagenb.org – boothby Jul 12 '11 at 20:29

# J, 30

*/0<(#,]*{.*1 _1$~#)2-/\a.i.":  A different approach than the other J answers.  */0<(#,]*{.*1 _1$~#)2-/\a.i.":461902
1
*/0<(#,]*{.*1 _1$~#)2-/\a.i.":708143 1 */0<(#,]*{.*1 _1$~#)2-/\a.i.":1010101
1
*/0<(#,]*{.*1 _1$~#)2-/\a.i.":123 0 */0<(#,]*{.*1 _1$~#)(}.-}:)a.i.":5
0


Would be 3 characters shorter if 5 were considered undulant.

-
 Well, at least I can console myself with the thought that I had the lead for an hour. :-) – Gareth Mar 24 '12 at 20:58

(pdf)eTeX, 129 chars

\def\a#1#2{\if#2?\ifx\r\s\def\s{1}\else
True\end\fi\fi\edef\t{\pdfstrcmp{#2}{#1}}\ifx\s\t
False\end\fi\let\s\t\a#2}\expandafter\a


Compiling with pdfetex filename.tex 1324? gives a pdf output. TeX is primarily a typesetting language, and outputting instead to stdout would take around 20 more chars. Also the strange requirement for one-digit numbers (false rather than true) takes me 26 chars.

-

## Python, 134 129 chars

def f(x):d=[cmp(*i)for i in zip(x,x[1:])]if x>9 else[0];n=d[0]>0;return all(i<0 for i in d[n::2])&all(i>0 for i in d[n<1::2])


Ungolfed:

def f(x):
if x>9:
d = [cmp(*i)for i in zip(x,x[1:])] #difference of x[i] and x[i+1]
else:
d = [0]       #trick to return False if x<10 using less chars
n = d[0]>0        #First digit is -1 or 1?
neg = d[n::2]     #negative numbers if x is Undulant
pos = d[not n::2] #positive numbers if x is Undulant

#check if all negs are -1 and all pos are 1 and return value
return all(i<0 for i in neg) and all(i>0 for i in pos)

-

## JavaScript, 88 chars

function _(i){i+='';c=i[0];f=i[a=x=1];for(g=f<c;d=i[x++];c=d)g^=a&=g?d<c:d>c;return!f^a}


In essence, turn the number into a string and compare adjacent characters, flipping the expectation for each.

-
In JavaScript, a function doesn't need a name and the question asks explicitly for a function, so you can save two characters. – rynah Jul 13 '11 at 14:34

# Python, 119 108

def u(x):l=[cmp(i,j)for i,j in zip(x,x[1:])];print x>9and all([i*j<0 for i,j in zip(l,l[1:])])and l!=[0]

-
Nice use of xor. You can cut quite a few characters out with ... for a,b in zip(t,t[1:]) rather than using ranges. Also, you don't need the brackets in all([...]) -- Python makes a generator when it finds (... for ...), even if the parentheses are for a function call. – boothby Jul 14 '11 at 7:50
Thank you very much for your advice! They have been very valuable! -20 chars – 0xKirill Jul 15 '11 at 8:12
Very nice solution. Few more characters x>9 and all(i^j for i,j in zip(l,l[1:])) and remove if l else False. – Ante Jul 16 '11 at 17:09
It is not working in all cases. Two cases are problematic: only 2 digits (e.g. 11), and last 2 digits are same and larger than one before (e.g. 12155). First problem is since there is no testing if x<100. Second is because 'one way comparison'. It can be fix with cmp(i,j) and instead i^j set i*j<0, and testing and l[0]!=0. Few more characters :-/ – Ante Jul 16 '11 at 17:24
Hmmm... print saves one character over return, but is it legitimate? The spec does ask for a function that "returns". – Gareth Rees Jul 17 '11 at 17:03
show 1 more comment

## Python 105101 100 chars

c=lambda r,t:len(r)<2 or(cmp(*r[:2])==t and c(r[1:],-t))
u=lambda x:x>9and c(x,cmp(*x[:2])or 1)


Recursive solution. c(r,t) checks if first char of r is less (t==-1) or greater (t==1) of second char, and call opposite check on shortened string.

-
 Nice. You can save a character in the first line by removing 0, and you can save three characters on the second line by writing u=lambda x:x>9 and c(x,cmp(*x[:2])or 1) – Gareth Rees Jul 17 '11 at 17:14 Tnx. I didn't like any() from the beginning :-) – Ante Jul 17 '11 at 20:31 You can save one more by writing x>9and. – Gareth Rees Jul 17 '11 at 21:35

## J, 44 39 36 31 characters

*/2(0<#@],0>*/\)*2-/\".;' ',.":


Usage as before.

I hadn't noticed that my last edit made the inequality with 0 check completely unnecessary. :-)

(0=+/2=/\u)*(1<#u)**/2~:/\2<:/\u=.".;' ',.":


Usage:

    (0=+/2=/\u)*(1<#u)**/2~:/\2<:/\u=.".;' ',.":461902
1


1. u=.".;' ',.": This reads in the number as a string ":, splits it into a list of characters preceded by spaces ' ',., stitches it back together ;, converts it back to numbers ". and then stores the result u=. This basically turns 461902 into 4 6 1 9 0 2 which I find easier to process in J.

2. */2~:/\2<:/\ This operates on the value stored in u. It takes each pair of characters and checks if the left one is less than or equal to the right one 2<:/\ so 4 6 1 9 0 2 becomes 1 0 1 0 1. It then takes the result of this and checks each pair of numbers for inequality 2~:/\ so 1 0 1 0 1 becomes 1 1 1 1. Finally it multiplies them all together to get either a 0 or a 1 */ At this point we could return the answer if it weren't for 2 things: a single digit returns 1 when the question requires a 0; and equal numbers are treated the same as 'less than' so 461900 returns 1 instead of 0. Bummer. On we go...

3. (1<#u) This checks if the number of items stored in u #u is greater than 1 and returns false if it's just a single digit number.

4. (0=+/2=/\u) This takes each pair of numbers stored in u and checks for equality 2=/\u. It then sums the answers and checks if it has 0.

The results of parts 2, 3 and 4 are then multiplied together to (hopefully) produce a 1 when the number meets the requirements specified in the question.

-
 Nice job re-taking the lead, but I just borrowed a trick from yours! – ephemient Mar 25 '12 at 17:56 (That being said, I think you could take my a.i.": to shave a few more characters off.) – ephemient Mar 25 '12 at 18:03 Unfortunately, I'm probably going to have to put that inequality check back in - my answer fails now for 11, 22, 33, 44 etc. – Gareth Mar 25 '12 at 19:57

## CoffeeScript, 9867 53

(n)->0!in((n[i]>=c^(n[0]<n[1])+i)%2for c,i in n[1..])


tests:

[
'01010101' # true
'12345'    # false
'1010101'  # true
'887685'   # false
'9120734'  # true
'090909'   # true
]


uncompressed:

undulant = (n) ->
direction = n[0] < n[1]
return n.split('').every (cur, i) ->
prev = arr[i-1] or 10 * direction
+(prev >= cur) is (direction+i)%2

-

# k (41 chars)

{(x>9)&~max(=). 1_'-':'1_'(<':;>':)@\:$x}  eg. {(x>9)&~max(=). 1_'-':'1_'(<':;>':)@\:$x}1212130659
1b

-

## Python, 155 chars

g=lambda a,b:all(x>y for x,y in zip(a,b))
u=lambda D:g(D[::2],D[1::2])&g(D[2::2],D[1::2])
def U(n):D=map(int,str(n));return(n>9)&(u(D)|u([-d for d in D]))

-

# C++, 94 chars

bool u(int N){int K,P,Q,U=1,D=1;while(N>9)P=N%10,Q=(N/=10)%10,K=D,D=U&Q<P,U=K&Q>P;return U^D;}


same method as my Erlang awnser with a for loop rather than recursion.

-

c=cycle[(<),(>)]
l!n=n>9&&and(zipWith3($)l(show n)$tail$show n) u n=c!n||((>):c)!n  -  I count only 83 characters in this solution. (Are you on Windows, perhaps? Write the file with unix line endings, which is legal Haskell.) – MtnViewMark Jul 16 '11 at 16:00 Thanks, I was using 'wc' to count my characters on Cygwin. I count 82 characters. I used the following code, as wc seems to be outputting an extra character. (Vim doesn't show a trailing newline, but notepad does...) readFile "Undulant.hs" >>= print . length . dropWhile (== '\n') . reverse . filter (/= '\r') – Thomas Eding Jul 18 '11 at 23:11 # Golfscript, 48 Hoping to beat J, my first time using Golfscript. Didn't quite succeed. [..,(<\1>]zip{..$=\-1%.$=-}%(\{.@*0<*}/abs  - # Perl/re, 139 Doing everything in regex is kind of a bad idea. /^(?:(.)(?{local$a=$1}))?(?:(?>((.)(?(?{$a lt$3})(?{local$a=$3})|(?!)))((.)(?(?{$a gt$5})(?{local$a=$5})|(?!))))*(?2)?)(?(?{pos>1})|(?!))$/


I'm using Perl 5.12 but I think this will work on Perl 5.10. Pretty sure 5.8 is out though.

for (qw(461902 708143 1010101 123 5)) {
print "$_ is " . (/crazy regex goes here/ ? '' : 'not ') . "undulant\n"; } 461902 is undulant 708143 is undulant 1010101 is undulant 123 is not undulant 5 is not undulant  - ## PowerShell, 88 Naïve and trivial. I will golf later. filter u{-join([char[]]"$_"|%{if($n){[Math]::Sign($n-$_)+1}$n=$_})-notmatch'1|22|00|^$'}

-

# JavaScript, 112

function(n,d,l,c,f){while(l=n%10,n=n/10|0)d=n%10,c?c>0?d>=l?(f=0):(c=-c):d<=l?(f=0):(c=-c):(c=d-l,f=1);return f}


You only need to pass it one argument. I could probably golf this further with a for loop.

-
 (d>=l -> d>0) and (d<=l -> d<2) perhaps? I'm not looking closely, as perhaps d might contain fractional parts that might skew it. – Thomas Eding Jul 18 '11 at 23:16 @trinithis: That's a lowercase L, not a 1. Thanks though! – rynah Jul 18 '11 at 23:54 Where's DejaVu Sans Mono or Bitstream Vera Sans Mono when you need it? Perhaps I need to customize stackoverflow with some custom css or a user script... – Thomas Eding Jul 19 '11 at 0:46 @trinithis: I agree, the font choice isn't that great. Bolding doesn't stand out enough... – rynah Jul 19 '11 at 4:07

# Erlang, 137123 118 chars

u(N)->Q=N div 10,u(Q,N rem 10,Q>0,Q>0). u(0,_,D,U)->D or U;u(N,P,D,U)->Q=N rem 10,u(N div 10,Q,U and(Q<P),D and(Q>P)).

-
 Won't this return True so long as there has been at least one up and one down transition anywhere? Won't it return True for, say 1234321? – MtnViewMark Jul 12 '11 at 2:36 @ MtnViewMark, yeah it did thanks, I misunderstood the question fixed now hopefully. – Bunnit Jul 12 '11 at 3:33

# Q, 71

{$[x>9;any all a=#[;(1 -1;-1 1)](#)a:1_signum(-':){"I"$x}each -3!x;0b]}


sample usage

q){$[x>9;any all a=#[;(1 -1;-1 1)](#)a:1_signum(-':){"I"$x}each -3!x;0b]} 5
0b
q){$[x>9;any all a=#[;(1 -1;-1 1)](#)a:1_signum(-':){"I"$x}each -3!x;0b]} 10101
1b
q){$[x>9;any all a=#[;(1 -1;-1 1)](#)a:1_signum(-':){"I"$x}each -3!x;0b]} 01010
1b
q){$[x>9;any all a=#[;(1 -1;-1 1)](#)a:1_signum(-':){"I"$x}each -3!x;0b]} 134679
0b
q){$[x>9;any all a=#[;(1 -1;-1 1)](#)a:1_signum(-':){"I"$x}each -3!x;0b]} 123456
0b
q){$[x>9;any all a=#[;(1 -1;-1 1)](#)a:1_signum(-':){"I"$x}each -3!x;0b]} 132436
1b

-
 You can logic away the if {(x>9)&any all a=#[;(1 -1;-1 1)](#)a:1_signum(-':)("I"$')($)x} gives 62 – slackwear Mar 23 '12 at 19:07 Never seen ($) syntax for string before and the logic is a nice touch. – tmartin Mar 26 '12 at 8:41 ## perl, 78 chars sub u{@_=split//,$_=shift;s/.(?=.)/($&cmp$_[$+[0]])+1/ge;chop;$#_&&!/00|1|22/}

-

## Scala 141, 133, 129 97:

def u(n:Int):Boolean=n>9&&{
val a=n%10
val b=(n/10)%10
a!=b&&n<99||(a-b*b-(n/100)%10)<0&&u(n/10)}


With a = n % 10, b = (n/10) % 10, c = (n/100) % 10

if a > b and b < c or
a < b and b > c


Then a-b * b-c is either x*-y or -x*y with x and y as positive numbers, and the product is in both cases negative, but for -x*-y or x*y (a < b < c or a > b > c) the product is always positive.

The rest of the code is handling special cases: one digit, two digits, two identical digits.

-
def is_undulant(n):
digits = [int(i) for i in list(str(n))]
diffs = []
for i in range(len(digits) - 1):
diffs.append(cmp(digits[i], digits[i+1]))
if len(diffs) == 1:
if diffs[0] == 0:
return False
else:
for i in range(len(diffs) - 1):
if diffs[i] * diffs[i+1] != -1:
return False
return True

-
 if you're writing Python2, you can use cmp instead of your diff function – JBernardo Jul 11 '11 at 20:55 Thanks, I had forgotten there is 'cmp'. – Tigrux Jul 12 '11 at 17:01 Aghh... I had not realized that the goal is to write in as few characters as possible. :-/ – Tigrux Jul 12 '11 at 17:05 digits = map(int,str(n)) – st0le Jul 15 '11 at 12:46

## PHP, 151 chars

function i($n){$n=str_split($n);@$p=$n[1]==null?:($m=($n[0]>=$n[1])?-1:1)*10;foreach($n as$k=>$v)if(($k%2*2-1)*($v-$p)*@$m<=0&$p=$v)return!1;return!0;}  ungolfed(-ish): function is_undulant($n){

$n=str_split($n);
@$p=$n[1]==null?:($m = ($n[0] >= $n[1])? -1 : 1)*10; foreach ($n as$k=>$v)
if ( ($k%2 * 2 - 1) * ($v - $p) * @$m <= 0 & $p=$v ) return !1;

return !0;
}

-

Different approach I think. 124 chars

def undulant(x):
x = x
return any((int(x[1])-int(x[0]))*-1**i*(int(x[i])-int(x[i-1]))>0 for i in range(2,len(x)))

-
 You should tell us what language that is. – user unknown May 4 '12 at 13:01

## Scala, 194 characters

def u(i:Int):Boolean={val x=i.toString;if(!x.matches("(\\d)\\1")){"(?<=.*)(\\d)(?=(\\d).*)".r.replaceAllIn(x,m=>if(m.group(1)<m.group(2))"<"else">").matches("((<>)+<?)|((><)+>?)\\d")}else false}


Hmm...regex seemed like a good idea at the time...

-
 Doing everything in regex is kind of a bad idea. (Your comment inspired me!) – ephemient Mar 25 '12 at 5:40

## C# 147 142

bool U(int i){if(i<10)return 0>1;var s=i+"";var b=s[0]>s[1];for(int j=2;j<s.Length;j++){var x=s[j-1]>s[j];if(x==b)return 0>1;b=x;}return 1>0;}
`

Working sample: http://ideone.com/b8ubr

-