Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

In Python, one can save bytes by aliasing functions that are used repeatedly. For example:

r=range
a=r(100)
b=r(200)
c=r(300)

However, when the functions are member functions together, I don't know how to alias them in a way that allows chaining. For example:

s='Hello'

// Plain code
s=s.replace('H','J').replace('e','i').replace('l','m').replace('o','y')

// What I am trying to do
q=replace
s=s.q('H','J').q('e','i').q('l','m').q('o','y')

Obviously, what I am trying to do isn't valid syntax. And neither is this:

q=s.replace
s=q('H','J') // Replaces the 'H' in 'Hello'
s=q('e','i') // Replaces the 'e' in 'Hello'... and the J is gone.
s=q('l','m')
s=q('o','y')

Is there a another way to alias member functions and chained functions that saves characters?

share|improve this question
    
Define your own class, with its method q meaning what replace means in the class your using. –  Ypnypn May 8 at 21:07
2  
I'm glad this hasn't been downvoted :) –  TheDoctor May 8 at 23:08
2  
I've unwikied all the answers for now, but we haven't reached a strong enough consensus to call for unwiki-ing this and similar questions. See also: meta.codegolf.stackexchange.com/q/1555/3808 –  Doorknob 冰 May 10 at 14:34
1  
Now that the aforementioned meta discussion is semi-official (or at least most of us agree), I've gone ahead and removed the wiki on this post. –  Doorknob 冰 May 13 at 21:58
1  
Your last version doesn't work. q is bound to the replace method of that specific str instance. Also, remember you can do single char replacements with "Hello".replace(*"HJ") –  gnibbler May 14 at 1:40

6 Answers 6

up vote 12 down vote accepted

No problemo! You can alias a method, but you have to know how to use it:

>>> r=str.replace
>>> a='hello'
>>> r(r(r(r(a,'h','j'),'e','i'),'l','m'),'o','y')
'jimmy'

The key is that you have to pass self explicitly, because the alias is a kind of function that takes an extra argument that takes self:

>>> type(r)
<type 'method_descriptor'>
share|improve this answer
2  
How did I not see this before? –  Rainbolt May 14 at 14:44

Define your own class, with a shorter method name.

For example, if you're using the method replace() belonging to the String class, you could make your own class S have a method called q which does the same thing.

Here is one implementation:

class m(str):
 def q(a,b,c):return m(a.replace(b,c))

Here is a much better implementation:

class m(str):q=lambda a,b,c:m(a.replace(b,c))

Use it like so:

s="Hello"
s=m(s).q('H','J').q('e','i').q('l','m').q('o','y')
share|improve this answer

You may use the reduce function.

reduce(lambda s,(a,b):s.replace(a,b),[('H','J'),('e','i'),('l','m'),('o','y')],'Hello')
share|improve this answer
    
If your answer different from this answer (as far as technique used, not necessarily written in the exact same form)? –  Rainbolt May 10 at 18:54
    
@Rusher It is different. E.g. the number of invocations is hard-coded in the linked answer while here it is given only by the length of the second argument (which can be any iterator). –  Howard May 10 at 20:36

This is a few characters shorter anyway

j=iter('HJeilmoy')
for i in j:s=s.replace(i,next(j))

even shorter for a small number of replacements is

for i in['HJ','ei','lm','oy']:s=s.replace(*i)

of course this just covers one particular case. However code golf is all about finding those special cases that can save you bytes.

It's possible to write a wrapper function that handles the general case, but the code will be too large to have a place in most code golf challenges.

You instead need to think "I can do this transformation efficiently (strokewise) with str.replace. Can I shift the internal representation of my solution to take advantage of that? (without wasting so many strokes to negate the advantage)"

share|improve this answer
    
I do like this answer because it describes good habits when golfing and definitely solves the specific example presented. I accepted another answer because it is applicable to the more general case. –  Rainbolt May 14 at 14:47

If you're doing a lot of replaces, you could do this:

s=''.join({'H':'J','e':'i','l':'m','o':'y'}[a] for a in list(s))
share|improve this answer
    
I was hoping for an answer that wasn't specific to replace. I just used that as an example. –  Rainbolt May 8 at 21:14
    
This can only replace 1 char at a time, but it can insert multi-char replacements. And this is not fully golfed (remove the space after [a]) –  Quincunx May 9 at 2:54
2  
Doesn't the [a] have to be replaced with .get(a,a) (otherwise, we get some Key Error thing)? And why have list(s) instead of s? –  Quincunx May 9 at 3:32

How about defining a lambda function?

r=lambda s,a,b:s.replace(a,b)

s=r(r(r(r(s,'H','J'),'e','i'),'l','m'),'o','y')
share|improve this answer
1  
No need: str.replace /is/ that lambda! See my answer. –  MtnViewMark May 14 at 14:34

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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