20
\$\begingroup\$

Randomly inspired by Numbers Increase While Letters Decrease

Given a list of mixed letters and integers (e.g., ['a', 2, 3, 'b']) increase the letters by one position in the alphabet (wrapping at z to a) and decrease the numbers by 1. For the above example, the output should be ['b', 1, 2, 'c'].

  • The input can be a mixed-type list, a delimited string, a list of strings, etc.
  • z wraps to a, but 1 goes to 0, and 0 goes to -1, etc.
  • The input will only ever be [a-z] and integers. You can choose capital letters [A-Z] as input if that's easier for you.
  • The input is guaranteed non-empty.
  • The input may contain only numbers or only letters.

Examples:

Input
Output

['a', 2, 3, 'b']
['b', 1, 2, 'c']

['a', 'b', 'z']
['b', 'c', 'a']

[-1, 0, 257, 'x']
[-2, -1, 256, 'y']

[0, 3, 1, 20382876]
[-1, 2, 0, 20382875]

Rules and Clarifications

  • Input and output can be given by any convenient method.
  • You can print the result to STDOUT or return it as a function result.
  • The output doesn't have to be the same format as the input (e.g., you could take input as a string and output as a list).
  • Either a full program or a function are acceptable.
  • If applicable, you can assume the input/output integers fit in your language's native int range.
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.
\$\endgroup\$
2
  • 1
    \$\begingroup\$ If the number is equal to Integer.MinValue or whatever the lowest value of a signed integer is in my language, should I underflow to Integer.maxValue or should I continue counting down? \$\endgroup\$
    – Nzall
    Commented Aug 23, 2019 at 14:10
  • 1
    \$\begingroup\$ @Nzall Undefined behavior. The 5th bullet point under Rules and Clarifications specifies that both input and output integers fit in your languages native int range, so you'd never get Integer.MinValue as an input. \$\endgroup\$ Commented Aug 23, 2019 at 14:28

30 Answers 30

6
\$\begingroup\$

05AB1E, 5 bytes

<AAÀ‡

Try it online!

<          # decrement the numbers
 A         # constant "abcdefghijklmnopqrstuvwxyz"
  AÀ       # same, but rotated left ("bcd...yza")
    ‡      # transliterate
\$\endgroup\$
5
\$\begingroup\$

Python 3, 59 bytes

lambda a:[i-1if''!=i*0else chr(97+(ord(i)+8)%26)for i in a]

Try it online!

-1 byte thanks to Erik the Outgolfer

\$\endgroup\$
5
  • 1
    \$\begingroup\$ 57 bytes. \$\endgroup\$ Commented Aug 22, 2019 at 13:50
  • \$\begingroup\$ @EriktheOutgolfer integer vs string comparison does not seem to be working in your solution. \$\endgroup\$
    – Jitse
    Commented Aug 22, 2019 at 13:54
  • \$\begingroup\$ Oh right, you need Python 2 for that. \$\endgroup\$ Commented Aug 22, 2019 at 13:55
  • \$\begingroup\$ Ah yes, then it seems to work. Still the replacement of -96 with +8 saves a byte. \$\endgroup\$
    – Jitse
    Commented Aug 22, 2019 at 13:57
  • \$\begingroup\$ ''!=i*0 is three bytes shorter than my str(i)>'9', good job \$\endgroup\$
    – Kateba
    Commented Aug 22, 2019 at 15:49
5
\$\begingroup\$

Perl 5 (-p), 17 bytes

y/a-z/b-za/or$_--

Try it online!

Bonus 19-byter:

$_>$_++?$_-=2:s/a//

TIO. This one features some cool tricks, but fails to beat the straightforward solution above.

\$\endgroup\$
5
\$\begingroup\$

Ruby, 34 bytes

For each element, attempt to return the element -1. Strings cannot do this, so they error out and are picked up by the rescue clause, which instead calls succ on it to return the next letter in the alphabet. succ "rolls over" on z and returns aa though, so we simply take the first character in the returned string.

->a{a.map{|e|e-1rescue e.succ[0]}}

Try it online!

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

JavaScript (Node.js), 55 bytes

a=>a.map(s=>1/s?s-1:B([(B(s)[0]+8)%26+97])+'',B=Buffer)

Try it online!

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

Python 3, 182 130 118 bytes

-51 bytes thanks to @AdmBorkBork and @Black Owl Kai, -1 byte thanks to @Black Owl Kai, -12 bytes by replacing .append() with +=[] and replacing n+1 with -~n

def a(x):
 b='abcdefghijklmnopqrstuvwxyz';c=[]
 for d in x:
  try:c+=[d-1]
  except:c+=[b[(-~b.find(d)%26)]]
 return c

Try it online!

I made this while the question was in the Sandbox but didn't see it posted until just now. :P

Ungolfed

def a(x):
    b = 'abcdefghijklmnopqrstuvwxyz'
    c = []
    for d in x:
        try:
            c.append(d - 1)
        except:
            c.append(b[((b.find(d) + 1) % 26)])
    return c

Explanation

For each element in the inputted list x, it tries to subtract 1 and add it to the eventual returned list. If an error occurs (because the element is a string), the letter's index in the alphabet is added by 1 and that mod 26 is taken. The mod 26 wraps an index of 26 back to 0.

\$\endgroup\$
6
  • \$\begingroup\$ Welcome to CodeGolf SE! I'm not an expert at Python, but I think you can swap 4 spaces for tabs to save a bunch of bytes. \$\endgroup\$ Commented Aug 22, 2019 at 15:27
  • \$\begingroup\$ I got it to 131 bytes just by eliminating whitespace. One further byte can be golfed by realizing that (x+27)%26 has the same result as (x+1)%26 \$\endgroup\$
    – Kateba
    Commented Aug 22, 2019 at 15:53
  • \$\begingroup\$ @AdmBorkBork BlackOwlKai Thank you for the help! I've edited the post. \$\endgroup\$ Commented Aug 22, 2019 at 16:12
  • \$\begingroup\$ You can use a ternary with str(d)==d to check if it's a string or not, instead of relying on try/except. Then, since you no longer need try/except, you can do the whole thing in a list comprehension! I'll let you think about it a little more but you can easily get under 100 bytes this way ;) \$\endgroup\$
    – Value Ink
    Commented Aug 22, 2019 at 23:38
  • \$\begingroup\$ 89 bytes \$\endgroup\$
    – Value Ink
    Commented Aug 23, 2019 at 21:32
2
\$\begingroup\$

J, 30 bytes

<: ::((26|>:)&.(_97+a.i.]))&.>

Try it online!

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

Gema, 55 characters

<N>=@sub{$1;1}
z=a
<L>=@int-char{@add{@char-int{$1};1}}

Dirty solution. Wrapping around on letter increment is painfully long, so got a separate rule.

Input can be quite anything, just use some separators. (You can even omit separators between numbers and letters. With the price of 1 character for changing to <L1> you could omit separators between letters too.)

Sample run:

bash-5.0$ gema '<N>=@sub{$1;1};z=a;<L>=@int-char{@add{@char-int{$1};1}}' <<< "['a', 2, 3, 'b']"
['b', 1, 2, 'c']

Try it online!

Gema, 66 characters

<N>=@sub{$1;1}
<L>=@cmpi{$1;z;@int-char{@add{@char-int{$1};1}};a;}

Clean solution. Half relatively efficient, then half pure pain.

Sample run:

bash-5.0$ gema '<N>=@sub{$1;1};<L>=@cmpi{$1;z;@int-char{@add{@char-int{$1};1}};a;}' <<< "['a', 2, 3, 'b']"
['b', 1, 2, 'c']

Try it online!

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

R, 77 85 bytes

Thanks @Giuseppe for a whooping 8 bytes

function(l)Map(function(x)"if"(i<-match(x,L<-c(letters,"a"),0),L[i+1],x-1),l)

Try it online!

Takes the input as a list. After a big change by @Giuseppe, this makes use of Map to apply a function to the list. It makes use of match to test for a character. During the test the extended letter list and index are saved for the return.

\$\endgroup\$
5
  • \$\begingroup\$ I suppose characters aren't finite because they are cast to numeric by is.finite and are thus NA? \$\endgroup\$
    – Giuseppe
    Commented Aug 22, 2019 at 20:38
  • \$\begingroup\$ @Giuseppe thought it would be something along those lines. Even though it's the same bytes as is.double I needed to use it :) \$\endgroup\$
    – MickyT
    Commented Aug 22, 2019 at 20:41
  • \$\begingroup\$ 77 bytes? \$\endgroup\$
    – Giuseppe
    Commented Aug 22, 2019 at 20:43
  • \$\begingroup\$ sorry to get rid of your is.finite, I thought I'd take a crack at it myself \$\endgroup\$
    – Giuseppe
    Commented Aug 22, 2019 at 20:43
  • 1
    \$\begingroup\$ @Giuseppe very nice, Wouldn't have thought of Map and match. It's good to learn something each day :) \$\endgroup\$
    – MickyT
    Commented Aug 22, 2019 at 20:49
2
\$\begingroup\$

MathGolf, 14 bytes

▄\╧¿ò'z=¿Å'a)(

Try it online!

Takes letter as lowercase.

Explanation

▄\╧              Is the element in the lowercase alphabet?
   ¿ò            If so:
     'z=           Is it equal to z?
        ¿Å         If so:
          'a         Push 'a'
            )      Else: Increment the string
             (   Else: Decrement the number
\$\endgroup\$
2
\$\begingroup\$

Retina, 52 50 48 58 41 37 bytes

T`zl`l
\b0
-
\d+
*
-_*
-$.0
_(_*)
$.1

-4 bytes thanks to @FryAmTheEggman (and for mentioning I had a bug: 1 → -1 instead of 1 → 0).
+10 bytes to fix a bug with 1 and 0.. Such an annoying edge case which screwed me over for quite a while.. But golfed it to 41 bytes now. (Now I'm curious about the <40 bytes versions @Neil and @CowsQuack mentioned in the comments.. Thanks @Neil for the tip of converting the 0 to -, and dealing with the negative values first. Converting those right back from unary to integer helped a lot.)
Apparently I don't need the boundaries at this point, so -4 bytes.. >.>

I/O is comma-separated.

Try it online.

Explanation:

Transliterate all "zabcdefghijklmnopqrstuvwxy(z)" to "abcdefghijklmnopqrstuvwxyz":

T`zl`l

Replace all standalone 0s with a -:

\b0
-

Convert all numbers to unary, by replacing them with that amount of underscores:

\d+
*

For all negative values, with zero or more unary-lines behind it: keep the minus sign, and get the total length of this match (including the -), converted back to an integer:

-_*
-$.0

As for the positive integers: match a positive integer by matching a single unary-line, followed by zero or more unary-lines. And then replace them with the length of that capture group to remove that single unary-line and convert them back to integers simultaneously:

_(_*)
$.1
\$\endgroup\$
0
1
\$\begingroup\$

SNOBOL4 (CSNOBOL4), 103 bytes

	U =&UCASE 'A'
N	X =INPUT	:F(END)
	U X @P	:F(D)
	U POS(P) LEN(1) . OUTPUT	:(N)
D	OUTPUT =X - 1	:(N)
END

Try it online!

\$\endgroup\$
1
\$\begingroup\$

PHP, 50 bytes

for(;''<$a=$argv[++$i];)echo$a<a?--$a:(++$a)[0],_;

Try it online!

Tests

Outputs letters/integers separated by _ with a trailing separator.

In PHP you can increment letters directly, so I took advantage of it. But the z is incremented to aa, to convert it to a, the (++$a)[0] is used which only outputs the first character of the incremented value.

\$\endgroup\$
1
\$\begingroup\$

Japt -m, 13 12 bytes

-1 byte thanks to Shaggy

;¤?UÉ:Cg8+Uc

Try it

Explanation:

;o ?UÉ:Cg8+Uc
-m              // Map U through the input:
 o              // Try to create a range [1...U]
   ?            //   If that creates a range (number):
    UÉ          //     Return U-1
      :         //   Else, return:
;      C        //     alphabet (a...z)
        g       //     Index:
         8+Uc   //       8 + char-code of U

Note: ; turns C into the lowercase alphabet

\$\endgroup\$
6
  • \$\begingroup\$ It doesn't look like this wraps from z to a. \$\endgroup\$
    – Shaggy
    Commented Aug 22, 2019 at 22:15
  • \$\begingroup\$ @Shaggy Whoops, I missed that. I added a temporary fix for +2 bytes \$\endgroup\$
    – Oliver
    Commented Aug 22, 2019 at 22:21
  • \$\begingroup\$ Couldn't figure out a way to fix mine (yet) without a ternary, which makes it too similar to yours for my liking so I'm deleting for now. o -> ¤ will save you a byte here. \$\endgroup\$
    – Shaggy
    Commented Aug 22, 2019 at 22:46
  • 1
    \$\begingroup\$ +2 and then -1 thanks to Shaggy would be more accurate! :D \$\endgroup\$
    – Shaggy
    Commented Aug 22, 2019 at 23:30
  • 1
    \$\begingroup\$ @Shaggy The +2 was thanks to Oliver :P \$\endgroup\$
    – Oliver
    Commented Aug 22, 2019 at 23:31
1
\$\begingroup\$

Haskell, 52 51 bytes

map q
q"z"="a"
q x|x>"`"=succ<$>x|1<2=show$read x-1

As Haskell doesn't allow lists of mixed types, letters and numbers are taken and returned as strings.

Try it online!

Check for every list element: if the string is "z", return "a"; if the first character of the string is > '`' (i.e. a letter, not a digit), return the successor of the char(s) in the string; else it must be number, so convert to an integer, subtract 1 and turn into a string again.

Edit: -1 byte thanks to @cole.

\$\endgroup\$
2
  • \$\begingroup\$ Does this work for 51 bytes? \$\endgroup\$
    – cole
    Commented Aug 23, 2019 at 3:07
  • \$\begingroup\$ @cole: yes it does. Thanks! \$\endgroup\$
    – nimi
    Commented Aug 23, 2019 at 5:00
1
\$\begingroup\$

Jelly, 13 bytes

®i‘ị®µ’e?€Øa©

Try it online!

Clever fix by Jonathan Allan.

Note: This is not a full program, the footer over TIO makes it possible to input using a command-line argument to test the function.

\$\endgroup\$
2
  • \$\begingroup\$ Wont work with negatives in the input (or over chr range). ®i‘ị®µ’e?€Øa© is a fix for zero I believe. \$\endgroup\$ Commented Aug 23, 2019 at 2:05
  • \$\begingroup\$ @JonathanAllan Hah, I forgot that doesn't exactly work in that case. Ironic, since I avoided using ~ as the condition to account for -1s in the input... Also, how am I going to shorten ®i‘ị®... \$\endgroup\$ Commented Aug 23, 2019 at 6:35
1
\$\begingroup\$

C++17 (gcc), 120 bytes

#define O int operator()
struct V{O(char&c){c++-90?:c=65;}O(int&i){--i;}};int f(auto&l){for(auto&x:l)std::visit(V{},x);}

Here f is the required function; l is both the input and output parameter, and it is expected to be a container of objects which are compatible with std::variant<char, int> or vice versa.

Try it online!

\$\endgroup\$
1
\$\begingroup\$

dzaima/APL, 21 20 bytes

{0::⍵-1⋄⎕l(⍳⊇1⌽⊣)⍵}¨

Try it online!

-1 thanks to ngn.

\$\endgroup\$
1
  • \$\begingroup\$ (⎕l⍳⍵)⊇1⌽⎕l -> ⎕l(⍳⊇1⌽⊣)⍵ \$\endgroup\$
    – ngn
    Commented Sep 14, 2019 at 11:11
1
\$\begingroup\$

K (oK), 27 bytes

{$[9+@x;`c$97+26!8+x;x-1]}'

Try it online!

-8 thanks to ngn and dzaima :)

\$\endgroup\$
7
  • 1
    \$\begingroup\$ 31 bytes {$[-9=@x;x-1;90=x;"A";`c$1+x]}' inlining the special-case & using uppercase (and the ' has to be counted as the input should be a list) \$\endgroup\$
    – dzaima
    Commented Sep 14, 2019 at 19:07
  • \$\begingroup\$ @scrawl i think dzaima is right - the ' should be counted. here's a slightly longer expression that doesn't need ' and also takes care of "z"->"a": {`c`i[t]$(-26*x~'"z")+x+1-2*t:x~'0+x} \$\endgroup\$
    – ngn
    Commented Sep 18, 2019 at 15:27
  • \$\begingroup\$ or even better - make a list of projections and apply them with @': {(`c$97+26!-96+;-1+)[x~'0+x]@'x}. here -96 (which is +1 minus the ascii code of "a") can be replaced with 8 as it's taken mod 26. \$\endgroup\$
    – ngn
    Commented Sep 18, 2019 at 15:40
  • \$\begingroup\$ another -1 byte by opting for capital letters: {(`c$65+26!14+;-1+)[x=_x]@'x} \$\endgroup\$
    – ngn
    Commented Sep 18, 2019 at 15:54
  • \$\begingroup\$ @dzaima yours can be shortened through -9=@x -> x=_x \$\endgroup\$
    – ngn
    Commented Sep 18, 2019 at 16:03
0
\$\begingroup\$

Runic Enchantments, 36 bytes

\$ka'~?*3({':+1\
R';$ >i::0Sqn=?/1-$

Try it online!

General process is to read input, prepend with a 0 (coercion to string), convert back to a number (single char will always return -1), compare with input. If same, it must be a numerical value, subtract 1 and print. If not same, it must be a char, subtract 1, compare with {. If less than, print, otherwise replace it with a and print.

Repeat until program performs a stack underflow.

Output is separated by ; in order to save 1 byte (and has a trailing one). Input is space-separated.

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

Stax, 17 bytes

àºÇ╝'♫d▬♣ΩÜEƒ6╩╬ó

Run and debug it

This feels like it should be possible to do shorter, but I can't resist the opportunity to use a new stax feature from the last release.

Treating the entire input as a string:

  1. Regex replace runs of digits with eval(match) - 1. This is the new feature, as the regex block replacement is not a string, but an integer.
  2. Regex replace runs of letters by ring-translating them around the lower-case alphabet.
\$\endgroup\$
0
\$\begingroup\$

Python 3, 66 bytes

lambda X:[x-1if type(x)==int else chr(97+(ord(x)+8)%26)for x in X]

Edit:

I didn't see the solution of Jitse until now. The trick of if''!=i*0 is awesome!

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

C#, 148 bytes

(object[] o)=>{var l=new List<object>();foreach(var h in o){try{l.Add((int)h-1);}catch{var c=((char)h+1);if(c>122){c=97;}l.Add((char)c);}}return l;}

Repl.it link

Ungolfed:

var inputList = new object[] {'a', 2, 'z', 6};
var outputList = new List<object>();
foreach (var currentItem in inputList)
{
    try
    {
        outputList.Add((int)currentItem-1);
    }
    catch
    {
        var currentItemPlusOne = ((char)currentItem + 1);
        if (currentItemPlusOne > 122)
        {
            currentItemPlusOne = 97;
        }
        outputList.Add((char)currentItemPlusOne);
    }
}
\$\endgroup\$
0
\$\begingroup\$

Charcoal, 16 bytes

WS⟦⎇№βι§β⊕⌕βιI⊖ι

Try it online! Link is to verbose version of code. Takes input on STDIN, each line being either a single lowercase letter or an integer, and outputs on separate lines on STDOUT. Explanation:

WS

Repeatedly input from STDIN until an empty line is reached.

Make this expression output on its own line.

⎇№βι

Is this a substring of the predefined lowercase alphabet?

§β⊕⌕βι

If so then print the next letter cyclically indexed.

I⊖ι

Otherwise decrement the value and cast back to string for implicit print.

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

Zsh, 47 bytes

a=({a..z} a)
for i
<<<${a[$a[(i)$i]+1]:-$[--i]}

Try it online!

a=({a..z} a)                  # append extra 'a' to the end to handle 'z' case
for i                         # for i in "$@" arguments
<<<${a[$a[(i)$i]+1]:-$[--i]}
       $a[(i)$i]              # first (i)ndex of $i in list (if not found, set to after last index)
      [         +1]           # increment
   ${a[           ]        }  # value in array at index. if lookup fails, empty string
   ${              :-$[--i]}  # if empty, decrement $i and substitute instead
<<<                           # print to stdout
\$\endgroup\$
0
\$\begingroup\$

C (gcc), 93 86 bytes

f(int**s){for(char**p=s,*z;z=*p++;)64&*z?*z=*z-'z'?++*z:97:sprintf(z,"%d",atoi(z)-1);}

Try it online!

The input is a NULL-terminated array of '\0'-terminated strings, e.g. {"a", "b", "c", "17", NULL}.

-7 bytes thanks to @ceilingcat

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

Perl 6, 31 bytes

*>>.&{(try $_-1)||chr ord ++$_}

Try it online!

Anonymous Whatever lambda that maps each element to the list and attempts to subtract one from it, otherwise incrementing it and taking the first character in the case that z wraps over to aa.

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

T-SQL 2012, 61 bytes

Capital letters needed in input.

Using table variable as input.

SELECT iif(x<'a',left(x-1,9),char((ascii(x)-64)%26+65))FROM @

Try it online

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

SimpleTemplate, 80 bytes

This was written on a language I've made.

Due to limitations in the compiler, I can't reduce it any more.

{@eachargv}{@if_ is matches"@\d+@"}{@incby-1_}{@echol_}{@else}{@inc_}{@echol_.0}

And now, ungolfed:

{@each argv as value}
    {@if value is matches "@\d+@"}
        {@inc by -1 value}
    {@else}
        {@inc by 1 value}
    {@/}
    {@echo value, "\n"}
{@/}

And the explanation:

  • {@each argv as value} - loops through all values in argv. (argv contains all the arguments passed).
    If the as <var> isn't present, the default _ variable is assumed.
  • {@if value is matches "@\d+@"} - checks that value matches with the regular expression "@\d+@".
  • {@inc by -1 value} - increments the value by -1 (basically, a decrement).
  • {@echo value, "\n"} and {@echol_} - echol outputs the values passed and appends a line at the end.
  • {@else} - self-explanatory
  • {@inc by 1 value} - increments the value by 1. If the by <value> is missing, it is assumed to be 1.
  • {@echo value.0, "\n"} and {@echol_.0} - echol outputs the values passed and appends a line at the end.
    This is required because of the challenge rules: z wraps to a.
    When an @inc is used on a string, it increments the chars and, once it hits z, it wraps to aa.
    Outputting the first character satisfies the challenge, at the cost of 7 bytes.
  • {@/} - closes the {@else} above (optional).
  • {@/} - closes the {@each} above (optional).

You can try this on: http://sandbox.onlinephpfunctions.com/code/7533641a0aa1fc8bf4699a9c758690de186b052f

Each passed argument to render() will be a new value that is considered.

\$\endgroup\$
-1
\$\begingroup\$

Perl, 64 bytes

foreach (@ARGV){$_=~m/[a-zA-Z]/?++$_:--$_;print substr $_,0,1;}
\$\endgroup\$

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.