53
\$\begingroup\$

Given an input string S, return truthy if all the letters in S are Lexically Ordered: their ASCII values need to be in either ascending or descending order. Return falsy in other cases.

Input

  • Input will be in the same case (all upper- or all lowercase). Your submission should be able to handle both.
  • Input will consist of ASCII in the range [A-Za-z] only
  • Input length will be at least 1, up to whatever maximum your language supports.
  • Input is a string - not a list of characters, not an array of ASCII-codepoints.

Output

  • Output should be true or false, or 0/1, or any other distinct true / false style output your language can provide.
  • All true cases need to have the same output, as well as all the false cases. No "False is 0, true is 1, 2, or 3".

Additional rules

  • Standard loopholes are forbidden
  • Answer must be a full program or a function, not a snippet or a REPL-entry.
  • , shortest answer in bytes wins.

Test cases

Truthy

"ABCDEF"
"ZYX"
"no"
"tree"   --> the multiple 'e's don't break the order
"q"

Falsy

"ABCDC"
"yes"
"deed"

Invalid

"Hello" --> invalid input - mixed case-, does not have to be handled
""      --> invalid input - length 0-, does not have to be handled
"\n
  "     --> invalid input - newline is not in range [A-Za-z]-, does not have to be handled
\$\endgroup\$
18
  • 1
    \$\begingroup\$ Can you clarify about the output: does the truthy value need be the same regardless of what input is given? \$\endgroup\$ Jan 30, 2017 at 19:12
  • 1
    \$\begingroup\$ @BusinessCat I've added a clarification. \$\endgroup\$
    – steenbergh
    Jan 30, 2017 at 20:01
  • \$\begingroup\$ What if your language's implementation of a string is a list of characters? Many of the answers posted here are using such languages... \$\endgroup\$
    – minseong
    Jan 30, 2017 at 20:40
  • 1
    \$\begingroup\$ If you really want distinct values for True and False you shouldn't say truthy or falsy. This implies that any values that evaluate to true or false are allowed. \$\endgroup\$
    – FlipTack
    Jan 30, 2017 at 21:50
  • 3
    \$\begingroup\$ related: Find the Wavy Words! \$\endgroup\$
    – Titus
    Jan 30, 2017 at 22:25

66 Answers 66

17
\$\begingroup\$

Python 2, 53 44 40 39 bytes

lambda a:`sorted(a)`[2::5]in(a,a[::-1])

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Nice, but it returns true for invalid values \$\endgroup\$ Feb 1, 2017 at 16:46
  • 7
    \$\begingroup\$ @PatrickBard mixed case is an invalid input, does not have to be handled \$\endgroup\$
    – Rod
    Feb 1, 2017 at 16:51
14
\$\begingroup\$

Haskell, 33 bytes

(%)=scanl1
f s=s==max%s||s==min%s

Try it online!

Thanks to Ørjan Johansen for 1 byte with aliasing scanl1 infix.

Haskell is an interesting language to golf sorting-based challenges because it does not have a built-in sort, barring a lengthy import Data.List. This encourages finding a way to do the task by hand without explicitly sorting.

The code uses scanl1, which folds an operation over the list from left to right, keeping track of the intermediate results. So, scanl1 max has the effect of listing the cumulative maxima of the list, i.e. the maxima of progressively longer prefixes. For example, scanl1 max [3,1,2,5,4] == [3,3,3,5,5].

The same with min checks whether the list is decreasing. The code checks the two cases and combines them with ||.

Compare to other expressions:

(%)=scanl1;f s=s==max%s||s==min%s

f s=or[s==scanl1 q s|q<-[min,max]]
f s=s==scanl1 max s||s==scanl1 min s
f s=any(\q->scanl1 q s==s)[min,max]
f s=any((==s).(`scanl1`s))[min,max]
f s=elem s$(`scanl1`s)<$>[min,max]
\$\endgroup\$
1
  • \$\begingroup\$ Actually your version with || wins if you define (?)=scanl1. \$\endgroup\$ Dec 17, 2017 at 20:59
11
\$\begingroup\$

Perl 6, 25 bytes

{[le] .comb or[ge] .comb}

How it works:

  • .comb splits the input into a sequence of characters.
  • le and ge are the "less or equal" and "greater or equal" string comparison operators.
  • [ ] around an infix operator, reduces ("folds") the argument list with that operator. (It's smart enough to return True if the input has only zero or one characters.)
  • or returns True if the expressions on either side of it is true.
\$\endgroup\$
10
\$\begingroup\$

JavaScript (ES6), 43 bytes

([...s],q=s+"")=>q==s.sort()|q==s.reverse()
\$\endgroup\$
5
  • \$\begingroup\$ Didn't know you could modify variables in the argument itself. Nice! \$\endgroup\$
    – Luke
    Jan 30, 2017 at 18:13
  • 1
    \$\begingroup\$ @Luke This is just a tricky use of default parameters: if you were to call the function with a second argument, q would be set to that value instead. \$\endgroup\$ Jan 30, 2017 at 19:50
  • \$\begingroup\$ I actually meant the spread operator which (in this case) converts it into an array right away. \$\endgroup\$
    – Luke
    Jan 30, 2017 at 20:05
  • \$\begingroup\$ Oh, OK. Yeah, destructuring assignments are really handy too ;-) \$\endgroup\$ Jan 30, 2017 at 20:09
  • \$\begingroup\$ Clever using the mutating .sort() to implicitly sort in the reverse check \$\endgroup\$
    – Cyoce
    Feb 2, 2017 at 1:56
9
\$\begingroup\$

05AB1E, 5 bytes

Â)¤{å

Try it online!

Explanation

Â)     # pair the input with it's reverse in a list
  ¤{   # get a copy of the reverse and sort it
    å  # check if the sorted copy is in the list of [input,reverse_input]
\$\endgroup\$
5
  • \$\begingroup\$ {¹å for 4, deleted my answer. Didn't notice the use of bifurcate, mine was too similar. \$\endgroup\$ Jan 30, 2017 at 17:46
  • \$\begingroup\$ @carusocomputing: that would unfortunately only check if the input is in the reverse of the sorted input. \$\endgroup\$
    – Emigna
    Jan 30, 2017 at 17:47
  • \$\begingroup\$ Or equal to the sorted input. aba => ['aab', 'baa'] => is in? => 0| aab => same => 1 \$\endgroup\$ Jan 30, 2017 at 17:47
  • \$\begingroup\$ @carusocomputing: The sorted input is ignored as it's below the reverse on the stack. You never pair them in a list. \$\endgroup\$
    – Emigna
    Jan 30, 2017 at 17:49
  • \$\begingroup\$ Coulda sworn bifurcate wrapped output; nvm, ignore me. \$\endgroup\$ Jan 30, 2017 at 17:50
7
\$\begingroup\$

MATL, 7 bytes

dZSuz2<

Try it online! Or verify all test cases.

d     % Implicitly input string. Push array of consecutive differences of code points
ZS    % Sign. Transforms each entry into 1, 0 or -1
u     % Unique
z     % Number of nonzeros
2<    % Is it less than 2? Implicit display
\$\endgroup\$
2
  • \$\begingroup\$ It returns true for all invalid cases \$\endgroup\$ Feb 1, 2017 at 16:35
  • 1
    \$\begingroup\$ @PatrickBard As the directions say, none of those need to be handled. \$\endgroup\$
    – Suever
    Feb 1, 2017 at 16:57
6
\$\begingroup\$

Jelly, 4 5 bytes

Ṣm0ẇ@

Try it online!

Originally was Ṣm0w at four bytes.

Explanation

Ṣm0ẇ@  Input: string S
Ṣ      Sort S
 m0    Concatenate sort(S) with reverse(sort(S))
   ẇ@  Sublist exists? Check if S is contained in the previous result
\$\endgroup\$
5
  • \$\begingroup\$ I was sure there was a four byter, but couldn't think of it! \$\endgroup\$ Jan 30, 2017 at 20:23
  • 2
    \$\begingroup\$ ...unfortunately the OP has clarified output is not truthy/falsy, but two distinct values. Four bytes still possible with though, I believe. Edit: ugh Ṣm0ẇ@. \$\endgroup\$ Jan 30, 2017 at 20:28
  • \$\begingroup\$ @JonathanAllan Unfortunate since it did meet the original rule of using the true/false style of the language. Another form might be Ṣẇm0$. If the argument order wasn't different for w and ... \$\endgroup\$
    – miles
    Jan 30, 2017 at 20:59
  • \$\begingroup\$ Nice, but it returns true on invalid values \$\endgroup\$ Feb 1, 2017 at 16:43
  • \$\begingroup\$ @PatrickBard Huh? '\n' and 'Hello' are perfectly valid values. \$\endgroup\$ Mar 12, 2017 at 12:04
6
\$\begingroup\$

Clojure, 47 bytes

#(let[c(map int %)a apply](or(a <= c)(a >= c)))
\$\endgroup\$
3
  • \$\begingroup\$ Couldn't figure out how to decide which operator to apply concisely. This is great. \$\endgroup\$ Jan 31, 2017 at 0:35
  • \$\begingroup\$ Wait you can put builtin function names into variables in Clojure? Huh, that's cool. It does make the <= and >= look infix though, which is really weird. \$\endgroup\$
    – clismique
    Feb 1, 2017 at 10:47
  • \$\begingroup\$ (let[+ *](+ 2 3)) = 6 :D It works on any function but apparently not on macros: "Can't take value of a macro" \$\endgroup\$
    – NikoNyrh
    Feb 1, 2017 at 12:01
6
\$\begingroup\$

C (gcc), 70 bytes

o(s,a)char*s;{for(a=0;s[1];s++)a|=s[1]-*s&64|*s-s[1]&32;return a!=96;}

I was hoping to find a shorter solution based on a recursive function, but it didn't work out due to the output requirement. So here's an imperative approach. At least, C's operator precedence works nicely for the inner loop statement.

Try it online!

\$\endgroup\$
6
\$\begingroup\$

R, 48 50 61 bytes

As an unnamed function

function(s)sd(range(sign(diff(utf8ToInt(s)))))<1

Thanks to @guiseppe for a few extra bytes.

charToRaw takes s and splits into a raw vector. This is converted to integers and a diff applied. sign makes the diffs a single unit. range reduces the vector to it's minimum and maximum. Then if the standard deviation sd is less than 1 it is TRUE

Try it online!

\$\endgroup\$
9
  • \$\begingroup\$ You can save 9 bytes using function(s,d=utf8ToInt(s))all(d==sort(d)) or function(s,d=utf8ToInt(s))!is.unsorted(d) \$\endgroup\$
    – mnel
    Feb 1, 2017 at 22:19
  • \$\begingroup\$ Or down to 34 bytes with !is.unsorted(utf8ToInt(scan(,''))) \$\endgroup\$
    – mnel
    Feb 1, 2017 at 22:24
  • \$\begingroup\$ @mnel unfortunately these do not handle the reverse sort eg cba and the last one would require a cat() to make it a full program \$\endgroup\$
    – MickyT
    Feb 1, 2017 at 22:59
  • \$\begingroup\$ Save 5 bytes with function(s)all(!diff(order(utf8ToInt(s)),,2)) (works with the reverse sort too!) \$\endgroup\$
    – mnel
    Feb 2, 2017 at 22:03
  • \$\begingroup\$ @mnel sorry again, that fails for tree \$\endgroup\$
    – MickyT
    Feb 3, 2017 at 0:42
5
\$\begingroup\$

MATL, 8 bytes

tPvGSXma

Try it Online!

Explanation

        % Implicitly grab the input as a string
tP      % Create a copy that is reversed
v       % Vertically concatenate these
GS      % Grab the input again and sort it
Xm      % Check if each row of the normal and reversed matrix is equal to the sorted one
a       % Check if either row matched
        % Implicitly display the result
\$\endgroup\$
2
  • \$\begingroup\$ Nice, but it returns true for '\n' and 'Hello' :/ \$\endgroup\$ Feb 1, 2017 at 16:41
  • 1
    \$\begingroup\$ @PatrickBard The input will be all the same case and will only be [A-Za-z] as stated in the initial post. They are in the "invalid" section because they explicitly don't need to be handled. \$\endgroup\$
    – Suever
    Feb 1, 2017 at 16:55
5
\$\begingroup\$

Mathematica, 33 bytes

0<=##||##>=0&@@ToCharacterCode@#&

Based on this tip. Unfortunately, I have to use ToCharacterCode instead of Characters, because <= and >= don't compare strings.

\$\endgroup\$
0
4
\$\begingroup\$

PowerShell, 61 bytes

param($a)$a-in-join(($b=[char[]]$a)|sort),-join($b|sort -des)

Try it online!

Takes input $a, then checks whether it's -in a two-element array. The array is formed by taking $a, casting it as a char-array, storing that in $b for later, piping it to sort-object which sorts lexically. The other element is $b sorted in -descending order.

\$\endgroup\$
4
\$\begingroup\$

Bash + coreutils, 59 bytes

f()(sed 's/\(.\)/\1\
/g'<<<$s|grep .|sort -c$1)
s=$1
f||f r

The input string is passed as an argument.

The output is returned in the exit code (0 for truthy, 1 for falsy, as usual), as allowed by PPCG I/O methods.

\$\endgroup\$
4
\$\begingroup\$

Brachylog, 5 bytes

I've tried to find a 4 bytes solution without success, so for now here's the most interesting 5 bytes solution I've found:

:No₎?

Try it online!

o, the ordering function, can take a parameter: 0 means ascending order, 1 means descending order. We set that parameter to an unbound variable N. Brachylog will try different values for N (only 0 or 1 are possible), try to unify the result with the input, and return whether any of those tries succeeded.

\$\endgroup\$
2
  • \$\begingroup\$ Seems to no longer work :( o?|o₁? works for an extra byte tho \$\endgroup\$
    – hakr14
    Aug 27, 2018 at 0:54
  • \$\begingroup\$ Seems to work if you replace the colon with a semicolon. Another one-byte-longer variant would be o{|↔}?. \$\endgroup\$ Mar 20, 2019 at 22:00
4
\$\begingroup\$

Perl, 35 bytes

Saved 4 bytes thanks to @Xcali directly, and 4 more indirectly.

31 bytes of code + -pF flag.

@b=reverse@a=sort@F;$_=/@a|@b/x

Try it online!

The code sorts the input, and checks if the inputs matches itself sorted (or in reverse order).

\$\endgroup\$
2
  • \$\begingroup\$ Slightly different method, but cuts it down to 38 bytes: Try it online! \$\endgroup\$
    – Xcali
    Dec 14, 2017 at 3:23
  • \$\begingroup\$ @Xcali Very nice, thanks. We can then get rid of $"=$, and use /x modifier instead to save 5 more bytes. \$\endgroup\$
    – Dada
    Dec 14, 2017 at 7:09
4
\$\begingroup\$

K (ngn/k), 19 bytes

{t:!#x;(t~<x)|t~>x}

Try it online!

A little bit lengthy. I have considered using inline assignment, but it seems to be on the same length as this one. Returns 0 for false and 1 for true.

Explanations:

{t:!#x;(t~<x)|t~>x}  Main function. Takes x as input
 t:                  Assign variable t to
   !                 Range between 0 to
    #x;              Length of x (exclusive)
       (  <x)        Ascended version of x
         ~           Matches (deep equal)
        t            Variable t
             |       Or
                >x   Descended version of x
               ~     Matches
              t      Variable t
\$\endgroup\$
3
\$\begingroup\$

Jelly, 5 bytes

,Ue@Ṣ

Try it online!

How?

,Ue@Ṣ - Main link: string
,     - pair string with
 U    - reverse(string)
    Ṣ - sorted(string)
  e@  - exists in with reversed arguments
\$\endgroup\$
3
\$\begingroup\$

Haskell, 54 50 bytes

t a=or[and(zipWith(<=)`f`tail$a)|f<-[(=<<),(<*>)]]

Usage example: t "defggh" -> True. Try it online!.

Maybe using sort like may other answers is shorter although it requires import Data.List. Here's a different approach:

For every function f from [(=<<),(<*>)], calculate and(zipWith(<=)`f`tail$a) and require any of the results to be True. The functions are

((=<<) (zipWith(<=)) tail) a
((<*>) (zipWith(<=)) tail) a

which both perform comparisons of neighbor elements of the input list a with <=, but one with the arguments flipped resulting in a >=. and checks if all comparisons are True.

\$\endgroup\$
3
\$\begingroup\$

PHP, 66 bytes

$a=$s=$r=str_split($argv[1]);sort($s);rsort($r);echo$s==$a|$r==$a;

takes input from command line argument. Run with -r.

\$\endgroup\$
3
\$\begingroup\$

Ruby, 44 bytes

->s{[s,s.reverse].include?s.chars.sort.join}

Try it online!

\$\endgroup\$
0
3
\$\begingroup\$

Racket, 93 bytes

(define(f s)(let([t(string->list s)])(or(equal?(sort t char<=?)t)(equal?(sort t char>=?)t))))

Try it online!

Ungolfed:

(define (lex-sorted? string)
  (let ([char-list (string->list string)])
    (or
     (equal? (sort char-list char<=?) char-list)
     (equal? (sort char-list char>=?) char-list))))

Using the sort then compare to original approach

\$\endgroup\$
3
\$\begingroup\$

Thunno 2, 5 bytes

r,sṠƇ

Attempt This Online!

Explanation

r,sṠƇ  # Implicit input
r,     # Pair the input with its reverse
  sṠ   # Sort the input
    Ƈ  # Is this in the list?
       # Implicit output
\$\endgroup\$
3
\$\begingroup\$

J-uby, 28 bytes

(:>>+(A|:==%:sort)&:any?)%:~

This is equivalent to the below Ruby code, with A equivalent to chars and :~ equivalent to reverse:

->s{[s,s.reverse].any?{_1.chars==_1.chars.sort}

Attempt This Online!

\$\endgroup\$
3
\$\begingroup\$

Arturo, 39 bytes

$->s[some?@[reverse<=split s]=>sorted?]

Try it!

$->s[                      ; a function taking an argument s
    some?@[...]=>sorted?   ; is at least one item in the list [...] sorted?
    split s                ; convert s from string to block of length-1 strings
    <=                     ; duplicate
    reverse                ; reverse; both stack items get trapped in the list
]                          ; end function
\$\endgroup\$
3
\$\begingroup\$

Nekomata + -e, 4 bytes

oᶜ↔=

Attempt This Online!

o       Sort
 ᶜ↔     Optionally reverse
   =    Check equality
\$\endgroup\$
3
\$\begingroup\$

K (ngn/k), 14 bytes

{^(<x;>x)?!#x}

Try it online!

Returns 0 for "truthy" inputs and 1 for "falsy" inputs.

  • !#x generate 0..len(x)
  • (<x;>x) create a two-length list containing the grade up and grade down of the input
  • (...)?... find the indices in the list; if the indices (as a whole) are not present, this returns 0N (the integer null). otherwise, the 0-based index of the matching element is returned (i.e. 0 or 1)
  • ^ null - returns 1 if its input is null, and 0 otherwise
\$\endgroup\$
2
\$\begingroup\$

MATLAB / Octave, 38 bytes

@(x)any(all([x;flip(x)]'==sort(x)',1))

Online demo

\$\endgroup\$
2
\$\begingroup\$

JavaScript (ES6) 74 62 50 47 43 bytes

([...a],b=a+'')=>b==a.sort()|b==a.reverse()

After some golfing and bugfixing, this answer ended up being pretty much the same as ETHProduction's, so please check his answer out and give it a +1.

\$\endgroup\$
5
  • \$\begingroup\$ Fixed the bug.. \$\endgroup\$
    – Luke
    Jan 30, 2017 at 18:02
  • 1
    \$\begingroup\$ You caught me, I posted the comment before editing... \$\endgroup\$
    – Luke
    Jan 30, 2017 at 18:04
  • \$\begingroup\$ I found the cause of the bug, and I now fixed it properly by arranging everything cleverly... \$\endgroup\$
    – Luke
    Jan 30, 2017 at 18:08
  • \$\begingroup\$ Bug is back... repl.it/FZrs/2 \$\endgroup\$
    – steenbergh
    Jan 30, 2017 at 18:12
  • 1
    \$\begingroup\$ Well, this is pretty much @ETHProduction's answer now, so I added a notice. Please +1 his answer. \$\endgroup\$
    – Luke
    Jan 30, 2017 at 20:14
2
\$\begingroup\$

Pushy, 7 bytes

ogoGo|#

Try it online!

Explanation:

      \ Implicit: Input on stack as charcodes
og    \ Check if the stack is sorted ascendingly (Push 0/1)
oG    \ Check if the stack is sorted descendingly (Push 0/1)
      \   - Note that this will work regardless of the first check, as input
      \     is guaranteed to be /[A-Za-z]+/
o|    \ Bitwise OR
#     \ Print the result
\$\endgroup\$
5
  • \$\begingroup\$ This does not return one distinct true-value. \$\endgroup\$
    – steenbergh
    Jan 30, 2017 at 18:35
  • 1
    \$\begingroup\$ @steenbergh No, but it satisfies our meta consensus on what counts as truthy or falsy - 1 and 2 are True in Pushy, whereas 0 is False. \$\endgroup\$
    – FlipTack
    Jan 30, 2017 at 19:11
  • \$\begingroup\$ If Pushy has a bitwise OR operator, that should work instead. \$\endgroup\$ Jan 30, 2017 at 19:20
  • \$\begingroup\$ @FlipTack I thought it was clear in the challenge, but I've now made it more specific: TRUE must output the same value on all testcases. Same goes for FALSE. \$\endgroup\$
    – steenbergh
    Jan 30, 2017 at 21:38
  • \$\begingroup\$ @steenbergh The meta consensus is there for a reason and makes sense, but if you insist... \$\endgroup\$
    – FlipTack
    Jan 30, 2017 at 21:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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