49
\$\begingroup\$

Pyth is a Python-inspired procedural programming language, created by PPCG user isaacg.

What general tips do you have for golfing in Pyth? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to Pyth.

One tip per answer, please.

\$\endgroup\$
0

24 Answers 24

26
\$\begingroup\$

Write the code in Python first

Pyth is so similar to Python that it is pretty easy to translate Python programs to Pyth. However, because Pyth is a single-letter-per-command language, it is sometimes hard to write straight Pyth. By writing in Python first, there is less to think about at a time (since Python is a pretty easy language to code in).

\$\endgroup\$
4
  • 1
    \$\begingroup\$ You could also mention that you can still use Python syntax in Pyth, so you can convert parts of the program individually or just use python if necessary. (As you did here) \$\endgroup\$ Commented Oct 20, 2014 at 15:07
  • \$\begingroup\$ @mbomb007 Download the Pyth interpreter and read through the documents. That's the only reliable way I know for writing a Pyth program. \$\endgroup\$
    – Justin
    Commented Feb 24, 2015 at 17:57
  • \$\begingroup\$ @mbomb007 Sorry; that's the way I learned how to write Pyth (looking through the source code). There is basically no documentation on Pyth; you basically have to learn the syntax by trial and error. \$\endgroup\$
    – Justin
    Commented Feb 24, 2015 at 18:22
  • \$\begingroup\$ Nowadays it might be better to write it in big-pyth format first since it can be translated instantly \$\endgroup\$
    – scpchicken
    Commented Sep 10, 2021 at 2:58
25
\$\begingroup\$

Know Your Variables

Pyth has 3 categories of variables: generic pre-initialized variables, variables pre-initialized based on user input, and variables that implicitly generate an assignment on first use.

Generic variables:

b = "\n"
d = " "
k = ""
G = "abcdefghijklmnopqrstuvwxyz"
H = {}                            # (empty dict)
N = '"'
T = 10
Y = []
Z = 0

Input-initialized variables:

Q = eval(input())
z = input()

Note that these initializations will only be run in a given program if the associated variable is used outside of a string in the code. In addition, the order is Q, then z, if both are used.

Assignment on first use variables:

J and K. If you want to initialize them both to the same value, you can do so with an expression such as KJ0, which is equivalent to the lengthier J0K0.

\$\endgroup\$
19
\$\begingroup\$

Use the even newer online interpreter to test your answers.

Note that this is new software, so it may be buggy. Please report any problems to me.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Awesome! I couldn't find this with google, just what I needed! \$\endgroup\$
    – user36219
    Commented Apr 3, 2015 at 17:31
  • \$\begingroup\$ The Heroku app is no longer available, I created a fork which is hosted here: pyth-docker.azurewebsites.net \$\endgroup\$
    – adrianus
    Commented Aug 21 at 17:47
14
\$\begingroup\$

Strings at the end of the line don't need end quotes. For example:

"Hello, world!

is a completely valid Hello World program.

\$\endgroup\$
2
  • \$\begingroup\$ Quite obvious really, it is the first google result for "Pyth programming language". Did you create your own page on esolangs? \$\endgroup\$
    – user36219
    Commented Apr 3, 2015 at 17:30
  • 3
    \$\begingroup\$ @theonlygusti Yes, I did. Also, it wasn't the first result last October. \$\endgroup\$
    – isaacg
    Commented Apr 3, 2015 at 17:33
10
\$\begingroup\$

Use C for base compression

This is actually undocumented, C on a string is actually not direct chr -> int but instead base 256 -> base 10 (which is the same on one char strings). This is hugely helpful in compressing an int, we can use this script to compress:

sCMjQ256

Take 12345678910, it results in ßÜ> (some unprintables in there).

Also with an array of ints, you can concatenate them, and with large strings by converting to code points and treating as base 128 number.

Another usage of C, thanks @xnor for showing me this, is making an arbitrary large number. The naive way is:

^TT

But we can do one byte better with:

CG

this base 256 deconverts the entire alphabet. Results 156490583352162063278528710879425690470022892627113539022649722 = ~1.56e62.

\$\endgroup\$
1
  • \$\begingroup\$ Added to doc now. \$\endgroup\$
    – isaacg
    Commented Jul 19, 2015 at 3:54
9
\$\begingroup\$

Use the short functional...err...functions

When the lambda argument to map or reduce just applies one operation to the arguments,, you can use the short forms, M and F. fMx is equivalent to mfdx, and fFx is the same thing as .UfbZx. For instance, say we take a list of numbers as input and output each one incremented. A first approach might be:

mhdQ

However, that can be rewritten as:

hMQ

A similar thing applies to reduce with F. As an example, say there's a challenge to calculate the product of a list of integers. Again, a first try may be:

.U*bZQ

However, with F, that can be shortened to:

*FQ

Shaves off three bytes...not bad!

\$\endgroup\$
1
  • \$\begingroup\$ And you don't need Q, as it is supplemented when the function is missing an input, making it *F \$\endgroup\$
    – Stan Strum
    Commented Sep 14, 2017 at 6:01
8
\$\begingroup\$

There is now an online tutorial for Pyth.

Full documentation will be added later.

\$\endgroup\$
7
\$\begingroup\$

Keep your Pyth implementation up to date.

I'm fairly regularly improving Pyth, removing less useful features and adding more useful ones, so keep an eye out for what's new and update your copy of the implementation regularly.

Some recently added features: (as of 10/19/14)

y: Acts as *2 on numbers, and as list of all subsets on strings and lists. For instance:

pyth -c 'y"abc'
['', 'a', 'b', 'c', 'ab', 'ac', 'bc', 'abc']

f: f is normally the filter command. Now, when called with a number as its second argument, it will filter over the infinite sequence starting with that number and counting up by ones, then return the first element of the resulting sequence.

For instance, here's the code to find the smallest prime over a billion:

pyth -c 'f!tPT^T9'
1000000007
\$\endgroup\$
5
  • \$\begingroup\$ Those look like useful additions, but what can you use instead of the old yz? mvdczd can't be the shortest way... \$\endgroup\$
    – Dennis
    Commented Oct 20, 2014 at 2:50
  • 1
    \$\begingroup\$ @Dennis I threw out the old y because I don't think Pyth needs to have multiple super-easily parsed input formats, just one, e.g. the Python format. So, yes, I think mvdczd will have to do, unfortunately. \$\endgroup\$
    – isaacg
    Commented Oct 20, 2014 at 2:54
  • \$\begingroup\$ @Dennis Problem solved, just added this to r's string processing suite. \$\endgroup\$
    – isaacg
    Commented Oct 21, 2014 at 16:06
  • \$\begingroup\$ r looks pretty useful. \$\endgroup\$
    – Dennis
    Commented Oct 21, 2014 at 17:07
  • \$\begingroup\$ @isaacg Sorry if this is off-topic, but I am wondering how to use the root operation @ in Fdr1+1@Q2Iq%Qd0d to make a factor calculator. When I try to use it, it defaults to the index meaning instead. Is there any way around this behavior? \$\endgroup\$ Commented May 2, 2016 at 3:04
5
\$\begingroup\$

Named arguments in functions (No longer supported)

Sometimes, default values in functions can be useful for golfing. Pyth actually supports this (much to my surprise). For example:

DC=Z1RZ;C;C5

Will print:

1
5

You can also use J and K to save characters when doing this:

DgJ1K1R+JKg;g2;g2 3

prints:

2
3
5

This is usually useful for recursive algorithms.

This no longer works, but I have left it here in case someone wants to golf using an old version of Pyth.

\$\endgroup\$
5
  • 17
    \$\begingroup\$ Wow - Even I didn't realize Pyth supported this, and I wrote the language! \$\endgroup\$
    – isaacg
    Commented Jan 12, 2015 at 10:19
  • \$\begingroup\$ Unfortunately, this no longer works in more recent versions of Pyth. \$\endgroup\$
    – isaacg
    Commented May 6, 2015 at 5:41
  • \$\begingroup\$ Should this tip be deleted like one of the other out-of-date tips? If not, maybe it should be marked with what version(s) this tip applies to. \$\endgroup\$
    – mbomb007
    Commented Aug 11, 2015 at 18:19
  • \$\begingroup\$ @mbomb007 I've been meaning to find the version, but I've been too lazy. Ill delete it if you think it is better off that way until I do find it. \$\endgroup\$ Commented Aug 12, 2015 at 12:50
  • \$\begingroup\$ @FryAmTheEggman I think it's up to you, since it says in the title that it's not supported. \$\endgroup\$
    – mbomb007
    Commented Aug 12, 2015 at 17:01
5
\$\begingroup\$

Look at all of the control flow options

Loops:

F: For loop. Just like Python's.

V: For loop over a range. Neither variable nor range must be given, so 2 characters shorter.

W: While loop. Just like Python's.

#: Infinite while loop. Escape with error or explicit break. Only try ... except feature now in Pyth.

Functions:

D: General define. Just like Python.

L: 1 argument, no assignment function, like Python's lambda, but named. Function name, variable name and return (R) need not be given, so 3 characters shorter.

Functional programming:

f: Filter - select elements of input sequence that return truthy on input lambda.

f: First integer greater than or equal to input which gives truthy filter result.

m: Map - transform elements of input sequence using input lambda.

u: Reduce - fold input sequence on input lambda, initializing accumulator to third argument.

o: Order - older elements of input sequence using input lambda as the key.

Usually, there will be multiple possibilities for any given problem, and only by writing test solutions with each of them can you figure out which is shortest.

\$\endgroup\$
3
  • \$\begingroup\$ .x can more recently be used for try-except blocks. \$\endgroup\$
    – mbomb007
    Commented Aug 11, 2015 at 18:24
  • \$\begingroup\$ @mbomb007 is there way to neglect except block, I mean can that be left empty? For ex: .x{some_statments}{except_block - can this be empty}. \$\endgroup\$ Commented Jan 2, 2017 at 15:32
  • \$\begingroup\$ @GurupadMamadapur # ... B can be used this way if you're not inside an expression \$\endgroup\$
    – isaacg
    Commented Jan 2, 2017 at 15:56
5
\$\begingroup\$

Unpacking 2 element tuples with F

Say you have a 2 element tuple, J = (a, b), and you want r(a,b), for some 2 arity function r.

The naive way to do this is rhJeJ.

The fancy way to do this is r.*J, using the unpack operator.

The really fancy way to do this is rFJ, using the fold operator.

\$\endgroup\$
2
  • \$\begingroup\$ is it still possible to use .u for that? .u seems to be cumulative reduce now. \$\endgroup\$
    – Ven
    Commented Feb 18, 2016 at 14:14
  • \$\begingroup\$ .u -> .* this was a change that was made a while ago, but was never updated. \$\endgroup\$
    – isaacg
    Commented Feb 18, 2016 at 16:26
4
\$\begingroup\$

Use the short arithmetic functions

h: Other than returning the first element of a list, it increments a number, e.g. hT evaluates to 11. Shorter than +1T.

t: This decrements a number (other than return the tail of a list), e.g. tT evaluates to 9. Shorter than -T1.

y: This doubles a number, e.g. yT evaluates to 20, shorter than *T2 or +TT.

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

Use map to generate lists

It's basically an equivalent of the fancy list comprehensions of python. Use an existing list or an range to iterate over and map each value, even if the value doesn't matter.

Two examples:

  • Generate a list of 8 zeros.

    mZ8 instead of *8]Z

  • Generate a list of 5 random numbers between 0 and 9:

    mOT5 instead of V5~Y]OT)

    The second one automatically assigns the list to Y (well actually it appends to Y), but even =YmOTU5 is shorter.

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

Implicit Q at EOF

This is a new change, as of today.

Q is the variable which is auto-initialized to the evaluated input. It is implicitly appended to the end of the Pyth program, as many times as is necessary to make the arity work out. To see an example of how to use this for golfing, let's say we want to compute the Collatz function of the input.

A shortest way to write it is like this:

@,/Q2h*3QQ

However, since the Qs are implicit at the end of the file, we can simply write:

@,/Q2h*3

Saving 2 bytes.

Note that functions with non-required arguments will not have those arguments filled in. For instance, c"12 12" will not have an implicit Q, since c only requires 1 argument.

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

Finding the maximum of two integers

g#

For instance, suppose you have J=5 and K=12. Then g#JK = 12, and g#KJ = 12 as well.

This was discovered by @Pietu1998, who put it this way:

Not sure if someone has already found it, but there's a cool way to do max(A, B) in 2 bytes, no need to use 3 for eS,AB. g#AB does the same thing. (It's very inefficient, though, since it loops max(1, A-B+1) times. An optimization is to put the number likely to be larger as B.)

\$\endgroup\$
1
  • \$\begingroup\$ @Jakube This is true. I apparently misthough something while typing this in chat. \$\endgroup\$ Commented Jun 4, 2016 at 15:01
3
\$\begingroup\$

Use reduce to apply a function repeatedly.

Suppose you need to set a variable to some function of itself, and repeat a certain number of times. Take, for instance, the problem of finding the number 100 later in the Collatz Sequence from the input. The shortest way to find the next number in the sequence, if the initial number is Q, is

@,/Q2h*Q3Q

The most obvious way to apply this 100 times and print the result would be

V100=Q@,/Q2h*Q3Q;Q

Loop 100 times, updating the value of Q each time, then end the loop and print Q.

Instead, we can use a reduce function which ignores the sequence variable (H).

u@,/G2h*G3GU100Q

This is 2 characters shorter. It is 3 characters shorter if you are trying to loop as many times as there are elements in a sequence.

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

There are usually shorter alternatives to Any

When you want to find if any of a sequence satisfy a condition, you would usually use .Em. For example, if you want to find out if any in a list are greater-than-or-equal to 5:

.Emgd5Q

But, if it only needs to be a truthy/falsey, not true/false, sm would work since sum works on bools.

smgd5Q

We can even do one shorter, with filter:

fgT5Q

The last one looks really ugly though.

For .All, the only thing I can think of is to use the opposite condition and negate it for a one char save over .Am:

!f<T5Q
\$\endgroup\$
3
\$\begingroup\$

Switching two elements in a list

Switching two elements can be quite an expensive task. So here are two approaches you wanna use.

Tmp-variable approach

In preparation we define a list Y and fill it with some numbers. The goal is to switch the second and third element.

=Y[1 3 5 3 6 7)AGH,1 2

We simply assign the tmp variable J = Q[G], do the first list assignment Y[G] = Y[H] and then the second last assignment Y[H] = J. The trick here is to nest the two list assignments, so you don't have to suppress printing and don't have to use refer twice to Y.

J@YGXXYG@YHHJ

instead of

J@YG XYG@YHXYHJ

Translating approach

If the elements, which you want to switch, are unique in the list, use this approach. It's really short. So this time we switch the first and third element (the values 1 and 5 are unique).

=Y[1 3 5 3 6 7)K,Z2

This uses the translation functionality of the list:

XYm@YdK)

This translating replaces every element Y[0] with Y[1] and every Y[1] with Y[0]. So if the values are not unique, bad things happend. For instance K,1 2 results in [1, 5, 3, 5, 6, 7].

Notice that the closing parentheses is optional, if the statement is the last one in your code.

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

Pyth's join method

The join method in Python can be often a little bit annoying, since it only joins strings. Pyth's join is more generous. It transforms all objects in strings by default.

E.g. jkUT gives 0123456789 or jb["abc"4,5\f]7 gives

abc
4
(5, 'f')
[7]
\$\endgroup\$
1
  • \$\begingroup\$ Recently, even more transforming-into-string functionality was added - the first argument is coerced to a string as well, e.g. j2\a\b -> "a2b" \$\endgroup\$
    – isaacg
    Commented Mar 27, 2015 at 15:07
2
\$\begingroup\$

Divisibility testing using I and GCD

Disclaimer: This only works for non-negative integers.

To check if two non-negative integers are divisible, you can do the following:

iI<divisor><dividend>

If a is divisible by b and a ≥ b ≥ 0, then gcd(a, b) = b.

It doesn't necessarily save bytes over !%<dividend><divisor>, but it might bring you a saving, because:

  • You might be able to tweak the implicit stuff at the end of a Pyth program (like dropping Q), when working with the dividend.
  • You can use it as a <pfn>, since it is a function on its own.
  • It handles modulo by 0.

Try it!

\$\endgroup\$
2
  • \$\begingroup\$ One more advantage: iI is a function on its own, whereas !% is not, so you can use it as a prefix function. \$\endgroup\$ Commented Dec 31, 2017 at 14:50
  • \$\begingroup\$ @EriktheOutgolfer Thanks, added to the list of advantages :) \$\endgroup\$
    – Mr. Xcoder
    Commented Dec 31, 2017 at 14:52
1
\$\begingroup\$

Telling if a Number is a Whole Number

A neat trick is using Invariant to tell if a number is a whole number as such:

sI

This checks if the number doesn't change when you truncate it, which it won't if it's a whole number.

For example, you can use this as a perfect square check:

sI@Q2
\$\endgroup\$
1
\$\begingroup\$

Debugging with <newline>

If your code is written in an imperative programming style, it is quite easy to debug, since you can easily print intermediate results. (permalink)

FN.:Q2                loop
      =Y+-Y-FNhN      some random command
                Y     print intermediate result
                 ;Y   end for loop and print result

But a large amount of Pyth programs use elements of functional programming, like map, filter and reduce, which don't allow such a simple printing. But it is still possible, using the \n command.

The same code using u (reduce) would be: (permalink)

u        .:Q2Y   reduce .:Q2, start with G = Y
 +-G-FHhH        random command

If you want to print the intermediate values, simply to insert \n: (permalink)

u         .:Q2Y   reduce
   \nG             print(G)
 +-\nG-FHhH        random command

\na prints a on a newline and returns a. So you can insert it anywhere without worrying changing the functionality of the program.

\$\endgroup\$
2
  • \$\begingroup\$ You can nowadays use the newline for this, which also prints a newline. \$\endgroup\$ Commented Jun 4, 2016 at 14:27
  • \$\begingroup\$ @Pietu1998 Yes, I use it all the time. Time to update the post. \$\endgroup\$
    – Jakube
    Commented Jun 4, 2016 at 14:33
1
\$\begingroup\$

Use Packed Pyth

Packed Pyth is a new "programming language" which is exactly the same as Pyth, except that it uses 7 bits per character instead of 8 bits per character.

To use it, clone the pyth repository. The file packed-pyth.py is the interpreter.

Say your code is "Hello, world!.

First, put it in a file: echo -n '"Hello, world!' > code.pyth

Next, pack the Pyth code into Packed Pyth file: python3 packed-pyth.py -p code.pyth code.ppyth

Finally, run the Packed Pyth code: python3 packed-pyth.py code.ppyth

When running code, you can provide the -d flag to see what the Pyth code that's actually being run is, and you can provide input as a second command line argument after the file containing the code.

Upside:

  • Code is shorter by 1/8th.

Downside:

  • ASCII only.

  • No interactive input.

  • Full debug options are not availible.

  • Worse error reporting.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ like we did for the safe mode thing, can we move it into a flag? \$\endgroup\$
    – Maltysen
    Commented Oct 6, 2016 at 2:48
  • \$\begingroup\$ This is awesome btw :D \$\endgroup\$
    – Maltysen
    Commented Oct 6, 2016 at 2:48
  • \$\begingroup\$ @Maltysen I think that would increase the byte score by one. \$\endgroup\$
    – isaacg
    Commented Oct 6, 2016 at 4:28
  • \$\begingroup\$ Can't Pyth be packed further since it only uses printable ASCII? \$\endgroup\$
    – lirtosiast
    Commented Nov 15, 2018 at 7:46
1
\$\begingroup\$

Assigning a variable to a function applied to itself

If you have a function of arity 1, and want to apply that to a variable and apply to itself, you can use the following syntax:

=<function><variable>

Instead of:

=<variable><function><variable>

For example, if you want to increment the variable Z, you can do:

=hZ

Which saves one byte over =ZhZ.

\$\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.