Code Golf Asked by RGS on December 15, 2020
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_3cdots 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}$$
Given an integer with 3 or more digits, output a Truthy value if the number is a mountain range number or Falsy otherwise.
A positive integer n
with 3 or more digits, in any reasonable format, e.g.
1324 -> Truthy
9191 -> Truthy
12121 -> Truthy
121212 -> Truthy
1212121 -> Truthy
19898 -> Truthy
(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 code-golf so shortest answer in bytes wins! Standard loopholes are forbidden.
Λ<0Ẋ*Ẋ-
Algorithm taken from the APL answer.
Λ<0Ẋ*Ẋ-
Ẋ- subtract pairs of consecutive elements
Ẋ* multiply pairs of consecutive elements
Λ return truthy value if all elements are:
<0 lesser than 0
Answered by Razetime on December 15, 2020
_.sliding(3).forall(t=>t(0)<t(1)&t(1)>t(2)|t(0)>t(1)&t(1)<t(2))
Checks whether for all sliding triplets the center is strictly larger (or strictly smaller) than the previous element and the next element.
Answered by cubic lettuce on December 15, 2020
all((d=diff(scan()))[1]*d*.5:-1>0)
Alternately reverses signs of all differences, and then multiplies them all by first difference: mountain range sequences will all be positive
Would be 40 bytes if defined as a function instead, so apologies to Robin with whom this would tie without the scan
for input.
Answered by Dominic van Essen on December 15, 2020
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!
Answered by S.S. Anne on December 15, 2020
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
Answered by begolf123 on December 15, 2020
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;}
Thanks to all in the comments for improvements - especially bit-shifting which I never would have thought of!!
Answered by simonalexander2005 on December 15, 2020
¬{s₃.o↙Ḋ}
Takes a list of digits as input.
¬{ } 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: ¬{…}
.
Answered by Fatalize on December 15, 2020
-nl
, 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)?$/
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/
Answered by Value Ink on December 15, 2020
f=lambda a,b,*l:l==()or(a-b)*(b-l[0])*f(b,*l)<0
Takes input splatted like f(1,2,3,4)
. Same idea as my second Haskell answer.
Answered by xnor on December 15, 2020
Answered by Chas Brown on December 15, 2020
&/0>2_*':-':$:
$:
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?
Answered by ngn on December 15, 2020
all(<0).g(*).g(-)
g=(=<<tail).zipWith
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.
f(a:b:t)=t==[]||(a-b)*(b-t!!0)<0&&f(b:t)
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
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]
Answered by xnor on December 15, 2020
XX2COqcm^m2COPD{0.<}al
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
Answered by DeathIncarnate on December 15, 2020
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))
Answered by Noodle9 on December 15, 2020
5 bytes saved thanks to Jo King & 1 byte thanks to Bubbler. Turning into a real team effort!
Prompts for list of digits:
×/0>2×/2-/⎕
Try it online! (Dyalog Classic)
Answered by Graham on December 15, 2020
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
}
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
Answered by David G. on December 15, 2020
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.
Answered by Neil on December 15, 2020
Answered by Jonah on December 15, 2020
a=>!a.some(p=v=>a*(a=p-(p=v))>=0)
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()
Answered by Arnauld on December 15, 2020
Answered by Jonathan Allan on December 15, 2020
Answered by Grimmy on December 15, 2020
all(<0).z(*).z(-)
z f(x:s)=zipWith(f)s$x:s
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)
Answered by 79037662 on December 15, 2020
crossed out 44 is still regular 44
-1 byte thanks to Giuseppe.
function(x,d=diff)all(d(sign(d(x)))^2>3)
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):
-1 byte thanks to Giuseppe.
function(x)all(s<-sign(diff(x)),rle(s)$l<2)
Computes the signs of the differences of consecutive digits. Then verifies that
Answered by Robin Ryder on December 15, 2020
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
Answered by RGS on December 15, 2020
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP