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 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 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


"tree"   --> the multiple 'e's don't break the order




"Hello" --> invalid input - mixed case-, does not have to be handled
""      --> invalid input - length 0-, does not have to be handled
  "     --> invalid input - newline is not in range [A-Za-z]-, does not have to be handled
  • 1
    \$\begingroup\$ Can you clarify about the output: does the truthy value need be the same regardless of what input is given? \$\endgroup\$ – Business Cat Jan 30 '17 at 19:12
  • 1
    \$\begingroup\$ @BusinessCat I've added a clarification. \$\endgroup\$ – steenbergh Jan 30 '17 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\$ – theonlygusti Jan 30 '17 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 '17 at 21:50
  • 3
    \$\begingroup\$ related: Find the Wavy Words! \$\endgroup\$ – Titus Jan 30 '17 at 22:25

57 Answers 57


05AB1E, 5 bytes


Try it online!


Â)     # 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]
  • \$\begingroup\$ {¹å for 4, deleted my answer. Didn't notice the use of bifurcate, mine was too similar. \$\endgroup\$ – Magic Octopus Urn Jan 30 '17 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 '17 at 17:47
  • \$\begingroup\$ Or equal to the sorted input. aba => ['aab', 'baa'] => is in? => 0| aab => same => 1 \$\endgroup\$ – Magic Octopus Urn Jan 30 '17 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 '17 at 17:49
  • \$\begingroup\$ Coulda sworn bifurcate wrapped output; nvm, ignore me. \$\endgroup\$ – Magic Octopus Urn Jan 30 '17 at 17:50

Python 2, 53 44 40 39 bytes

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

Try it online!

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

Haskell, 33 bytes

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]
  • \$\begingroup\$ Actually your version with || wins if you define (?)=scanl1. \$\endgroup\$ – Ørjan Johansen Dec 17 '17 at 20:59

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.

JavaScript (ES6), 43 bytes

  • \$\begingroup\$ Didn't know you could modify variables in the argument itself. Nice! \$\endgroup\$ – Luke Jan 30 '17 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\$ – ETHproductions Jan 30 '17 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 '17 at 20:05
  • \$\begingroup\$ Oh, OK. Yeah, destructuring assignments are really handy too ;-) \$\endgroup\$ – ETHproductions Jan 30 '17 at 20:09
  • \$\begingroup\$ Clever using the mutating .sort() to implicitly sort in the reverse check \$\endgroup\$ – Cyoce Feb 2 '17 at 1:56

MATL, 7 bytes


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
  • \$\begingroup\$ It returns true for all invalid cases \$\endgroup\$ – Patrick Bard Feb 1 '17 at 16:35
  • 1
    \$\begingroup\$ @PatrickBard As the directions say, none of those need to be handled. \$\endgroup\$ – Suever Feb 1 '17 at 16:57

Clojure, 47 bytes

#(let[c(map int %)a apply](or(a <= c)(a >= c)))
  • \$\begingroup\$ Couldn't figure out how to decide which operator to apply concisely. This is great. \$\endgroup\$ – Carcigenicate Jan 31 '17 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 '17 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 '17 at 12:01

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!


R, 48 50 61 bytes

As an unnamed function


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!

  • \$\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 '17 at 22:19
  • \$\begingroup\$ Or down to 34 bytes with !is.unsorted(utf8ToInt(scan(,''))) \$\endgroup\$ – mnel Feb 1 '17 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 '17 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 '17 at 22:03
  • \$\begingroup\$ @mnel sorry again, that fails for tree \$\endgroup\$ – MickyT Feb 3 '17 at 0:42

MATL, 8 bytes


Try it Online!


        % 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
  • \$\begingroup\$ Nice, but it returns true for '\n' and 'Hello' :/ \$\endgroup\$ – Patrick Bard Feb 1 '17 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 '17 at 16:55

Jelly, 4 5 bytes


Try it online!

Originally was Ṣm0w at four bytes.


Ṣ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
  • \$\begingroup\$ I was sure there was a four byter, but couldn't think of it! \$\endgroup\$ – Jonathan Allan Jan 30 '17 at 20:23
  • 1
    \$\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\$ – Jonathan Allan Jan 30 '17 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 '17 at 20:59
  • \$\begingroup\$ Nice, but it returns true on invalid values \$\endgroup\$ – Patrick Bard Feb 1 '17 at 16:43
  • \$\begingroup\$ @PatrickBard Huh? '\n' and 'Hello' are perfectly valid values. \$\endgroup\$ – Erik the Outgolfer Mar 12 '17 at 12:04

Mathematica, 33 bytes


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


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.


Perl, 35 bytes

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

31 bytes of code + -pF flag.


Try it online!

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

  • \$\begingroup\$ Slightly different method, but cuts it down to 38 bytes: Try it online! \$\endgroup\$ – Xcali Dec 14 '17 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 '17 at 7:09

Jelly, 5 bytes


Try it online!


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

Bash + coreutils, 59 bytes

f()(sed 's/\(.\)/\1\
/g'<<<$s|grep .|sort -c$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.


PHP, 66 bytes


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


Ruby, 44 bytes


Try it online!


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!


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

Using the sort then compare to original approach


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:


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.

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

MATLAB / Octave, 38 bytes


Online demo


JavaScript (ES6) 74 62 50 47 43 bytes


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.

  • \$\begingroup\$ Fixed the bug.. \$\endgroup\$ – Luke Jan 30 '17 at 18:02
  • 1
    \$\begingroup\$ You caught me, I posted the comment before editing... \$\endgroup\$ – Luke Jan 30 '17 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 '17 at 18:08
  • \$\begingroup\$ Bug is back... repl.it/FZrs/2 \$\endgroup\$ – steenbergh Jan 30 '17 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 '17 at 20:14

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.


Pushy, 7 bytes


Try it online!


      \ 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
  • \$\begingroup\$ This does not return one distinct true-value. \$\endgroup\$ – steenbergh Jan 30 '17 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 '17 at 19:11
  • \$\begingroup\$ If Pushy has a bitwise OR operator, that should work instead. \$\endgroup\$ – ETHproductions Jan 30 '17 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 '17 at 21:38
  • \$\begingroup\$ @steenbergh The meta consensus is there for a reason and makes sense, but if you insist... \$\endgroup\$ – FlipTack Jan 30 '17 at 21:39

Pyth, 5 bytes


A program that takes input of a "quoted string" and prints True or False as appropriate.

Test suite

How it works

}Q_BS   Program. Input: Q
}Q_BSQ  Implicit variable fill
 Q      Is Q
}       in
    SQ  Q sorted
   B    or
  _     Q sorted reversed?
        Implicitly print
  • \$\begingroup\$ You can save a byte (and become the shortest answer) by replacing }Q with /, which uses an implicit Q. \$\endgroup\$ – isaacg Mar 9 '17 at 18:33

Octave, 24 bytes


Try It Online!


GNU sed, 97 + 1(r flag) = 98 bytes

If the letters are ordered, the script returns 1, otherwise 0. In sed there are no data types.

s:$: zyxwvutsrqponmlkjihgfedcba:
s:(.*(.)(.).* ).*\2.*\3.*:\1abcdefghijklmnopqrstuvwxyz:i

To check if all letters are arranged in ascending order, I do a table lookup of each pair of consecutive letters in a descending alphabet, that is I try to find a counter example. Note that // actually repeats the last regular expression match! (see lines 2 and 3)

Run example: the script can test multiple input words, one per line

me@LCARS:/PPCG$ echo -e "tree\nABCDC" | sed -rf word_ordered.sed

CJam, 12 11 bytes


Try it online!


q            Push the input
 _$          Duplicate and sort
   _W%       Duplicate and reverse
      +      Concatenate the sorted and the reversed strings
       \     Bring input to the top
        #    Find the index of the input in the other string; returns -1 if not found
         )   Increment
          g  Signum (coerces to 0 or 1)

8086 machine code, 68 61 48 46 45 39 bytes

00000000  b2 31 be 82 00 ac 9f 88  c3 ac 3c 0d 74 14 38 c3  |.1........<.t.8.|
00000010  74 f5 e3 03 b1 00 9f 77  05 9e 76 ea eb 03 9e 77  |t......w..v....w|
00000020  e5 4a b4 02 cd 21 c3                              |.J...!.|

Assembled from:

org 0x100
    mov dl, 0x31
    mov si, 0x82
a:  lahf
b:  mov bl, al
    cmp al, 0x0d
    je y
    cmp bl, al
    je b
    jcxz @f
    mov cl, 0
@@: ja @f
    jbe a
    jmp n
@@: sahf
    ja a
n:  dec dx
y:  mov ah, 0x02
    int '!'

Scala, 47 bytes

def f(x:String)=x==x.sorted|x==x.sorted.reverse

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.