Mountain range numbers

22

3

Mountain range number

A number is a mountain range number if the inequalities satisfied by their consecutive digits alternate. In a way, looking at the number's digits should exhibit a /\/\/\... or a \/\/\/... pattern.

More formally, if our number n has \$k\$ digits

$$n = d_1d_2d_3\cdots d_k$$

then n is a mountain range number if

$$\begin{cases}d_1 > d_2 \\ d_2 < d_3 \\ d_3 > d_4 \\ \cdots \end{cases} \vee \begin{cases}d_1 < d_2 \\ d_2 > d_3 \\ d_3 < d_4 \\ \cdots \end{cases}$$

Your task

Given an integer with 3 or more digits, output a Truthy value if the number is a mountain range number or Falsy otherwise.

Input

A positive integer n with 3 or more digits, in any reasonable format, e.g.

  • Integer
  • String
  • List of digits

Test cases

Truthy

1324 -> Truthy
9191 -> Truthy
12121 -> Truthy
121212 -> Truthy
1212121 -> Truthy
19898 -> Truthy

Falsy

(Added another Falsy test case as per the comments, some answers might not cover the 4422 test case)

123 -> Falsy
321 -> Falsy
4103 -> Falsy
2232 -> Falsy
1919199 -> Falsy
4422 -> Falsy

This is so shortest answer in bytes wins! Standard loopholes are forbidden.

RGS

Posted 2020-02-06T16:19:51.257

Reputation: 5 047

1May we take input as a list of digits rather than an integer? – Robin Ryder – 2020-02-06T17:03:06.640

2@RobinRyder yes you may – RGS – 2020-02-06T17:10:14.590

Dupe? – AdmBorkBork – 2020-02-06T19:01:43.760

2@AdmBorkBork this one has an input relaxation (k>=3); also the other challenge is so old that many of the answers there wouldn't be close to competitive on this one; I'd actually rather remove the old one as a dupe of this. – Giuseppe – 2020-02-06T19:27:40.223

1@Giuseppe That's what I was leaning towards as well, hence why I didn't hammer it. I have now just hammered the old one. Thanks! – AdmBorkBork – 2020-02-06T19:52:03.560

1Related with a source restriction – Jo King – 2020-02-07T00:39:58.593

Suggested test case: [4,4,2,2] (or 4422 if you prefer). – Chas Brown – 2020-02-07T00:58:13.043

@ChasBrown thanks for the suggestion. why would you say 4422 is a nice test case here? – RGS – 2020-02-07T08:49:04.323

Answers

4

R, 44 40 bytes

crossed out 44 is still regular 44

-1 byte thanks to Giuseppe.

function(x,d=diff)all(d(sign(d(x)))^2>3)

Try it online!

Computes the differences of the signs of the differences of the input. These must all be equal to 2 or -2, i.e. the square must equal 4; checking that the square is >3 is sufficient.

If two consecutive digits are equal, there will be a 0 in the signs of differences, leading to a difference of signs of differences equal to 1 or -1. If three consecutive digits are in ascending or descending order, then the corresponding differences will be of the same sign, leading to a difference of signs of differences equal to 0. If neither of these occurs, the number is a mountain range number.


Old version (included as it might be golfable):

R, 44 43 bytes

-1 byte thanks to Giuseppe.

function(x)all(s<-sign(diff(x)),rle(s)$l<2)

Try it online!

Computes the signs of the differences of consecutive digits. Then verifies that

  • none of the signs are 0s (would correspond to 2 equal consecutive digits);
  • the runs of the signs are all equal to 1, i.e. no 2 consecutive signs are equal.

Robin Ryder

Posted 2020-02-06T16:19:51.257

Reputation: 6 625

1Good job, I like the usage of the run length function! +1 – RGS – 2020-02-06T17:23:42.057

all(.^2>3) is a bit shorter, since we know that the absolute value of the diff of the signs is bounded between -2 and 2. – Giuseppe – 2020-02-06T19:22:50.527

similarly, for your old version, you can do rle(s)$l<2 since we know there aren't zero-length runs. – Giuseppe – 2020-02-06T19:28:29.750

@Giuseppe Thanks! – Robin Ryder – 2020-02-06T20:14:13.207

4

05AB1E, 6 bytes

¥ü*0‹P

Try it online!

With truthy and falsy reversed, this would be 5 bytes:

¥ü*dZ

TIO

Grimmy

Posted 2020-02-06T16:19:51.257

Reputation: 12 521

Good job! +1 Why would the truthy <> falsy reversal make it shorter? – RGS – 2020-02-06T17:38:04.190

3@RGS 05AB1E has a single-byte built-in for x >= 0, but not for its negation x < 0. – Grimmy – 2020-02-06T17:39:17.877

I see, thanks for the tip. – RGS – 2020-02-06T17:40:04.047

I've used your answer to golf my answer in the same challenge with source restriction. If you want to post it as your own answer there I will of course revert back to my 7-byter and allow you to.

– Kevin Cruijssen – 2020-02-07T07:38:54.560

4

JavaScript (ES6),  35  33 bytes

a=>!a.some(p=v=>a*(a=p-(p=v))>=0)

Try it online!

Commented

a =>                // a[] = input list of digits,
                    //       re-used to store the last difference 
  !a.some(          //
    p =             // initialize p to a non-numeric value
    v =>            // for each v in a[]:
      a * (         //   multiply a by
        a =         //     the new value of a defined as
          p -       //       the difference between p and
          (p = v)   //       the new value of p, which is v
      )             //
      >= 0          //   the test fails if this is non-negative
  )                 // end of some()

Arnauld

Posted 2020-02-06T16:19:51.257

Reputation: 111 334

+1 for your weird expression used. I haven't been around for a long time but I keep noticing you like to post JS answers! JS does incredibly well at golfing, does it not? – RGS – 2020-02-06T19:07:09.120

Also, could you explain a bit what is going on in x=p=v=>x*(x=p-(p=v))>=0 ? – RGS – 2020-02-06T19:07:47.837

1@RGS We assign the arrow function v=>... to both x and p. Because this is non-numeric, the arithmetic operations in which these values are involved will result in NaN which is neither >=0 or <0. So the first 2 iterations will always be falsy, which is the expected behavior. – Arnauld – 2020-02-06T19:16:56.930

2@RGS Initializing variables this way in the callback of a loop is a rather common trick in JS (err... I mean golfed JS, obviously). This also works if we want them to be zero'ish in some bitwise operations. – Arnauld – 2020-02-06T19:22:03.677

ah I get it! Thanks for the explanation! – RGS – 2020-02-06T19:22:30.450

3

Japt -!, 7 bytes

Takes input as a digit array.

äÎä* dÄ

Try it

Shaggy

Posted 2020-02-06T16:19:51.257

Reputation: 24 623

Don't flags usually add up to the byte count? – RGS – 2020-02-06T17:12:40.123

2Your code currently gives a truthy value for 122, which is not a mountain range number. – RGS – 2020-02-06T17:14:03.263

1

@RGS Flags used to be part of the byte count indeed, but now there's consensus that they can be used for free (Personally I don't like that, but...)

– Luis Mendo – 2020-02-06T17:32:22.263

@LuisMendo They can be used but they count as a different language. – S.S. Anne – 2020-02-06T20:01:27.840

@RGS, fixed. And if you'd followed the link I very deliberately include with the flags in all my solutions ... – Shaggy – 2020-02-06T22:54:15.457

@Shaggy you are absolutely right! But I didn't even notice the link on the flags was different from the link on the language name :/ +1 now that the answer is right :) – RGS – 2020-02-06T22:55:47.417

3

Haskell, 57 55 47 44 42 bytes

all(<0).z(*).z(-)
z f(x:s)=zipWith(f)s$x:s

Try it online!

Takes input as a list of digits.

  • -2 by swapping the order of s and x:s

  • -8 by using a different helper function

  • -3 by using partial application and pointfree code

  • -2 by excluding f= from the submission (which I didn't realize was allowed :P)

xnor improved my answer using >>=.

79037662

Posted 2020-02-06T16:19:51.257

Reputation: 1 739

2Good job on this one! I like Haskell :D +1 – RGS – 2020-02-06T17:39:05.150

3

Python, 47 bytes

f=lambda a,b,*l:l==()or(a-b)*(b-l[0])*f(b,*l)<0

Try it online!

Takes input splatted like f(1,2,3,4). Same idea as my second Haskell answer.

xnor

Posted 2020-02-06T16:19:51.257

Reputation: 115 687

Ah wow, you guys keep surprising me every time! +1 – RGS – 2020-02-07T09:04:51.987

2

Jelly, 7 6 bytes

A benchmarking solution.

A monadic link taking as input the list of digits

I×Ɲ<0Ạ

You can try it online or verify all test cases.

I         Take the forward differences
  Ɲ       and for each pair,
 ×        multiply them together.
   <0     Check if those are below 0.
      Ạ   Check if this array of booleans only contains Truthy values.

-1 byte thanks to @79037662

RGS

Posted 2020-02-06T16:19:51.257

Reputation: 5 047

2I don't know Jelly, but could it be shorter to simply check for negativity, instead of taking the sign and then checking it's equal to -1? – 79037662 – 2020-02-06T17:31:55.873

@79037662 yes it would! Thanks for the alert! – RGS – 2020-02-06T17:37:00.133

1Nice answer. However, in general I’d consider holding back from answering your own question for a few days; as far as I understand that’s the general etiquette here. – Nick Kennedy – 2020-02-06T18:54:34.550

@NickKennedy oh sorry, will do so for the next challenges. Thanks for letting me know. – RGS – 2020-02-06T18:58:00.330

@RGS no worries! And nice challenge. – Nick Kennedy – 2020-02-06T19:20:10.673

2

Bash, 147 144 bytes

M(){
a=${1:0:1}
d=x
i=1
while [ $i -lt ${#1} ]
do
b=${1:$i:1}
case $d$((a-b)) in
[ux]-*)d=d;;*0|u*|d-*)return 1;;*)d=u;;esac
a=$b
let i++
done
}

Try it online!

I seem to like trying shell submissions, and learned some bash-isms in golfing this one.

$((a-b)) is equivalent to $(( $a - $b )) -- apparently you don't need the $ inside a $(( )) construct.

There is a ++ operator, works in $(( )) and in let

Subtracting letters is accepted, strangely. One of my samples in the TIO reads "xy", and apparently $((a-b)) evaluates a to x, and then variable x to an empty string and the empty string as numeric zero, and comparable for b and y. If I set x and y in the environment, those values are used.

Edit: -3 bytes by not putting whitespace after ;;, thanks to S.S.Anne

David G.

Posted 2020-02-06T16:19:51.257

Reputation: 541

+1 nice submission! – RGS – 2020-02-06T22:09:18.490

1@RGS I think it is a very nice touch that you are commenting on (and upvoting) each answer. Thank You. +1 – David G. – 2020-02-06T22:25:50.807

Thanks David! I just want to acknowledge every submission ;) – RGS – 2020-02-06T22:39:01.093

Do you need the newlines in case and while? – S.S. Anne – 2020-02-09T19:06:32.897

@S.S.Anne You need separation of the in and do tokens from the surrounding tokens. It can be space or newline or semicolon (though before "do" doesn't allow space). For the case statement, it can be the optional ( as well. Where you do not need separation is after the ;;. Saved three bytes. Thank You. – David G. – 2020-02-09T19:20:58.000

No, sorry, those are syntax errors. – S.S. Anne – 2020-02-09T19:36:25.527

1@S.S.Anne My output looks like my input because the trailer code deliberately matches the format from the original sample data. – David G. – 2020-02-09T19:38:36.237

exit instead of return and omitting the newlines before and after brackets won't work. I thought I was reading the output but I was reading the input, sorry. – S.S. Anne – 2020-02-09T19:40:12.037

1@S.S.Anne I tested it too, and must have done the same thing. Reverted back to 144. Ah well. – David G. – 2020-02-09T19:45:46.733

2

Haskell, 37 bytes

all(<0).g(*).g(-)
g=(=<<tail).zipWith

Try it online!

Takes the zipWith-based answer of 79037662 and generalizes out the pattern of

g(?) = \s->zipWith(?)(tail s)s

that applies the operator (?) to pairs of adjacent elements. This is shortened to the pointfree g=(=<<tail).zipWith.

We first apply g(-) to the input to take differences of consecutive elements, then g(*) to take products of those consecutive differences. Then, we check that these products are all negative, which means that consecutive differences must be opposite in sign.


Haskell, 40 bytes

f(a:b:t)=t==[]||(a-b)*(b-t!!0)<0&&f(b:t)

Try it online!

The idea is a bit clearer to see in the slightly less-golfed form:

42 bytes

f(a:b:c:t)=(a-b)*(b-c)<0&&f(b:c:t)
f _=1>0

Try it online!

We check that the first three digits (a,b,c) have the a->b steps and b->c steps going opposite directions by checking that the differences a-b and b-c have opposite signs, that is, their product is negative. Then we recurse to the list without its first element until the list has fewer than 3 elements, where it's vacuously true.

An alternative to check suffixes directly turned out longer:

43 bytes

f l=and[(a-b)*(b-c)<0|a:b:c:t<-scanr(:)[]l]

Try it online!

xnor

Posted 2020-02-06T16:19:51.257

Reputation: 115 687

Good job, as per usual. +1 because I see functions I know used in weird ways – RGS – 2020-02-07T00:27:56.183

Nice answer, I didn't know about =<<. – 79037662 – 2020-02-07T00:34:36.237

@79037662 And nice method from you! It looks like you converged to basically that same answer. I didn't think of doing this problem mostly pointfree -- I thought it would be long compared to the explicit recursion. – xnor – 2020-02-07T00:41:56.140

2

Python 2, 65 58 bytes

lambda A:all((x-y)*(y-z)<0for x,y,z in zip(A,A[1:],A[2:]))

Try it online!

Chas Brown

Posted 2020-02-06T16:19:51.257

Reputation: 8 959

Nice solution with the zip function +1 and this one handles gracefully the 1 and 2 digit cases (probably not the only answer here doing that, but this one I can easily spot ;) ) – RGS – 2020-02-07T09:03:35.087

2

Ruby -nl, 57 41 bytes

Replaces each character in the input string with the cmp comparison (<=> in Ruby) between it and the next character $'[0] (if there is no next character, remove the character instead). Then, check if the resulting string consists entirely of alternating 1 and -1.

gsub(/./){$&<=>$'[0]}
p~/^1?(-11)*(-1)?$/

Try it online!

Old Solution, 57 bytes

Check for duplicate consecutive numbers first by checking if the input string matches /(.)\1/ and inverting it. If no such pairs are found, replace each character with true or false based on whether its cmp style comparisons (<=>) to the character before it $`[-1] and after it $'[0] are not equal. (If there is no character before or after it, the <=> returns nil, which is definitely not equal to whatever the other character comparison returns.) Finally, it checks if the result does not contain an f (meaning no falses were returned).

p ! ~/(.)\1/&&gsub(/./){($`[-1]<=>$&)!=($&<=>$'[0])}!~/f/

Try it online!

Value Ink

Posted 2020-02-06T16:19:51.257

Reputation: 10 608

Really cool answer +1 ! – RGS – 2020-02-07T09:05:56.000

Doesn't work for 212 – G B – 2020-02-07T09:48:16.680

@GB found the regex error. Fixed for no byte count change. – Value Ink – 2020-02-07T23:54:02.573

2

Excel (Insider build ver. 1912), 122 Bytes

A1 'Input
B1 =SEQUENCE(LEN(A1))
C1 =MID(A1,B1#,1)
D1 =SIGN(IF(NOT(B1#-1),C1-C2,C1#-INDEX(C1#,B1#-1)))
E1 =(SUM(D1#)=D1*ISODD(LEN(A1)))*PRODUCT(D1#) 'Output

Returns ±1 (truthy) or 0 (falsy)

Explanation (can add more detail if people are interested)

B1 =SEQUENCE(LEN(A1)) ' Generates a spill array from 1 to the length of the input
C1 =MID(A1,B1#,1) ' Splits characters into rows. Using each value in the spill array B1#
                  ' as a charcter index
D1 =SIGN(IF(NOT(B1#-1), ' Choose different value on the first cell
           C1-C2, ' Use the opposite of the first difference between digits
           C1#-INDEX(C1#,B1#-1))) ' get the difference between each digit and the previous
E1 =(SUM(D1#)=D1*ISODD(LEN(A1))) ' Sum the digit differences, if the 
                                 ' input length is even check if 0, else check if equal to
                                 ' thefirst row of the differences
       *PRODUCT(D1#))            ' ensure there aren't any repeated digits

Tests

enter image description here

begolf123

Posted 2020-02-06T16:19:51.257

Reputation: 531

Hey there, thanks for your Excel submission! Very unusual :D +1 – RGS – 2020-02-07T23:57:01.063

1

Jelly, (5?) 6 bytes

5 if we may invert the truthy/falsey output (strip the trailing ¬).

IṠIỊẸ¬

Try it online!

Jonathan Allan

Posted 2020-02-06T16:19:51.257

Reputation: 67 804

Really clever solution! +1 it took me a bit to understand why you wanted to use the after the second I but then I realized you were building the opposite result – RGS – 2020-02-06T19:04:50.680

Fun fact, the codepoints of this answer themselves (in Jelly encoding) are also a mountain/dale (same as this answer on the source-restriction challenge).

– Kevin Cruijssen – 2020-02-07T07:27:16.783

1

J, 15 bytes

[:*/0>2*/\2-/\]

Try it online!

-7 bytes thanks to RGS's technique

Jonah

Posted 2020-02-06T16:19:51.257

Reputation: 8 729

Nice submission :) what does RGS's technique mean? +1 – RGS – 2020-02-06T22:11:11.120

1Meaning the logic is essentially the same as yours, translated into J, and was shorter than the initial approach i tried – Jonah – 2020-02-06T23:01:48.670

1

Charcoal, 29 27 bytes

UMθ⁻ι§θ⊕κUMθ×ι§θ⊕κ›⁰⌈…θ⁻Lθ²

Try it online! Link is to verbose version of code. Takes input as a list of digits and outputs as a Charcoal boolean (- for a mountain range number, otherwise no output). Explanation:

UMθ⁻ι§θ⊕κ

Take consecutive differences (cyclic, so includes difference between last and first digit).

UMθ×ι§θ⊕κ

Take consecutive products (again, cyclic).

›⁰⌈…θ⁻Lθ²

All results bar the last two must be negative.

Neil

Posted 2020-02-06T16:19:51.257

Reputation: 95 035

Interesting submission! +1 – RGS – 2020-02-06T22:10:01.663

1

APL+WIN, 17 15 bytes

2 bytes saved thanks to Jo King

Prompts for list of digits:

×/1=0>×2×/-2-/⎕

Try it online! Courtesy of Dyalog Classic

Graham

Posted 2020-02-06T16:19:51.257

Reputation: 3 184

Good job on this one! +1 – RGS – 2020-02-06T22:11:36.247

Is there a point to assigning the input to n? – Jo King – 2020-02-07T09:47:39.750

Jo. No! There is no point. It was left over from an earlier version. Old age :( Thanks for spotting it. – Graham – 2020-02-07T16:32:38.250

1

Python 3, 101 \$\cdots\$ 103 94 bytes

Added 13 bytes to fix error kindly pointed out by @ChasBrown.
Saved 9 bytes thanks to @ChasBrown!!!

def f(l):x=[a<b for a,b in zip(l[1:],l)];return all(a!=b for a,b in zip(x[1:]+l[1:],x[:-1]+l))

Try it online!

Noodle9

Posted 2020-02-06T16:19:51.257

Reputation: 2 776

Interesting submission! +1 – RGS – 2020-02-06T23:40:43.063

94 bytes – Chas Brown – 2020-02-07T01:17:16.323

@ChasBrown Nice one zip auto truncates the larger - thanks! :-) – Noodle9 – 2020-02-07T01:27:29.917

1

Burlesque, 22 bytes

XX2COqcm^m2COPD{0.<}al

Try it online!

XX      # Explode into digits
2CO     # 2-grams ("abc"->{"ab" "bc"})
qcm^m   # Compare each via UFO operator
2CO     # 2-grams
PD      # Product
{0.<}al # All less than 0

DeathIncarnate

Posted 2020-02-06T16:19:51.257

Reputation: 916

Nice answer. It looks kind of funny +1 can't you save some bytes by taking a list of digits as input? – RGS – 2020-02-06T23:49:20.263

1It makes very little difference, as I'd need to parse them with ps or pe anyway. This sneakily operates on strings and relies on ASCII comparison. – DeathIncarnate – 2020-02-06T23:51:31.720

1

K (ngn/k), 14 bytes

&/0>2_*':-':$:

Try it online!

$: as string

-': subtract (as ascii codes) each prior; implicit 0 before first

*': multiply by each prior; implicit 1 before first

2_ drop first 2 elements

&/0> all negative?

ngn

Posted 2020-02-06T16:19:51.257

Reputation: 11 449

The TIO link has 16 bytes? Is it 'cuz you assign your function to f? +1 for the good work :D – RGS – 2020-02-07T00:29:12.847

1@RGS thanks. yes, by convention function naming is not counted unless it's used for (non-anonymous) recursion. here i use the name f only for testing. – ngn – 2020-02-07T00:33:43.500

1

Brachylog, 9 bytes

¬{s₃.o↙Ḋ}

Try it online!

Takes a list of digits as input.

Explanation

¬{      }       It is impossible…
  s₃            …to find a subsequence of 3 elements…
    .o↙Ḋ        …which is already ordered

Slight subtility: o↙Ḋ is used to check whether the digits are increasing or decreasing. By default, o (which is the same as o₀) is for increasing order, and o₁ is for decreasing order. By using o↙Ḋ ( being an integer between 0 and 9), we check that the whole predicate is impossible for o₀, or o₁, or o₂, …, o₉. o₂ to o₉ are not implemented and thus will fail, which doesn’t impact the program as a whole.

If true. is an acceptable falsy value, and false. an acceptable truthy value (which I don’t think it should be), then you should be able to remove these 3 bytes: ¬{…}.

Fatalize

Posted 2020-02-06T16:19:51.257

Reputation: 32 976

Thanks for your submission! And I agree with you, using "false" as a Truthy value and vice versa is questionable :p it looks like a lot of answers would've benefited from that, though. +1 – RGS – 2020-02-07T14:00:42.090

1

Java (JDK), 95 83 bytes

p->{int i=0,j=1;for(;p.length>-~++i;)j=(p[i-1]-p[i])*(p[i]-p[i+1])<0?j:0;return j;}

Try it online!

Thanks to all in the comments for improvements - especially bit-shifting which I never would have thought of!!

simonalexander2005

Posted 2020-02-06T16:19:51.257

Reputation: 1 157

Thanks for your submission! +1 for you. You can save 7 bytes by using 0/1 as Falsy/Truthy values!

– RGS – 2020-02-07T15:28:00.337

Thanks! I hadn't thought to do that – simonalexander2005 – 2020-02-07T15:33:47.963

you may be able to shave 2 more bytes by returning nothing for Falsy. I think that is still reasonable. – RGS – 2020-02-07T15:42:07.877

An index shift could possibly save three further bytes.

– Jonathan Frech – 2020-02-07T16:18:50.800

1

C (gcc), 59 bytes

d;m(int*s){for(d=*s/s[1];s[1]&&s[1]/ *s-d;d^=1)s++;s=s[1];}

Takes as input a wide string of digits and returns zero if that number is a mountain range number.

-12 bytes thanks to ceilingcat!

Try it online!

S.S. Anne

Posted 2020-02-06T16:19:51.257

Reputation: 1 161

@ceilingcat Thanks! – S.S. Anne – 2020-02-09T20:13:37.367

+1 for the cool submission, but can you help me understand how the return here works? – RGS – 2020-02-09T20:13:39.737

@RGS Closest I can find is https://codegolf.stackexchange.com/a/106067/89298. It exploits GCC's behavior when compiling without optimization in which temporary results are stored in the return register.

– S.S. Anne – 2020-02-09T20:15:23.330