-4

I have a few lines of code for making a rotated string for a Caesar cipher and just for fun I am trying to condense them into one. Obviously this is pointless since it is completely unreadable but I'm curious. Still, I can't quite figure out how to do it. Here's what I have tried so far

s = 'abcdefghijklmnopqrstuvwxyz'
rot = raw_input('Enter Rotation or Key: ')
s = s[-int(rot):] + s[:-int(rot)] if rot.isdigit() else rot.lower()+ ''.join([j for i in s for j in rot.lower() if j == i]) # This is the only line I want condensed
print s

Here is the readable version which actually works

s = 'abcdefghijklmnopqrstuvwxyz'
rot = raw_input('Enter Rotation or Key: ')
if rot.isdigit():                        #I only want from here
    s = s[-int(rot):] + s[:-int(rot)]
else:
    for i in rot.lower():
        s = s.replace(i,'')
    s = rot.lower() + s                  #To here condensed into one line
print s

rot is the amount to rotate the alphabet or the key for a keyed version of a Caesar cipher. You should be able to just run the code as is and see exactly what's wrong

I know this is bad code but I find this kind of code interesting since the language supports linking so many if/else/for/lambda/whatever together into a single line.

SirParselot
  • 2,640
  • 2
  • 20
  • 31
  • 5
    Why do you want it to be a one-liner? You lose readability and gain nothing. – Markus Meskanen Aug 13 '15 at 14:43
  • 1
    @MarkusMeskanen To quote OP: *“Obviously this is kind of pointless since it is completely unreadable but **I'm curious**.”* (emphasis mine). It’s just about playing around. – poke Aug 13 '15 at 14:48
  • 1
    @poke I understand that he's just curious, but what he's doing is plain stupid (no offense, I've done it too myself). Look at my answer, you could have one function instead, keep the readability, lose nothing. There's no need to be curious on writing bad code. – Markus Meskanen Aug 13 '15 at 14:50
  • 1
    Why do you want to condense the code? It looks like a stupid question. – skyking Aug 13 '15 at 15:00
  • I want to condense it into one line because I see code like this all the time and I struggle to read it so I am trying to write bad code so I can understand bad code. It's also very interesting to me that the language supports linking so many if/else/for/lambda/whatever together. – SirParselot Aug 13 '15 at 15:05
  • @MarkusMeskanen I gain the knowledge of how to do it that is enough of a reason to ask. – SirParselot Aug 13 '15 at 15:13

4 Answers4

1

You can rewrite the else case using reduce (it’s functools.reduce in Python 3):

if rot.isdigit():
    s = s[-int(rot):] + s[:-int(rot)]
else:
    s = rot.lower() + reduce(lambda x, y: x.replace(y, ''), rot.lower(), s)

And then you can combine it to one line:

s = s[-int(rot):] + s[:-int(rot)] if rot.isdigit() else rot.lower() + reduce(lambda x, y: x.replace(y, ''), rot.lower(), s)

But you’re absolutely right: It makes no sense to write it like this. It’s really unreadable.


Since you’re using Python 2, you can actually use str.translate here too, to remove the characters in rot from s. This uses the deletechars parameter of that function:

s = rot.lower() + s.translate(None, rot.lower())

Your one-line expression is then a little bit shorter:

s = s[-int(rot):] + s[:-int(rot)] if rot.isdigit() else rot.lower() + s.translate(None, rot.lower())
poke
  • 369,085
  • 72
  • 557
  • 602
  • That doesn't do the same thing as the original. – skyking Aug 13 '15 at 14:44
  • @skyking that is what I was looking for. I only wanted the if else statement condensed and I updated my question to portray that better. – SirParselot Aug 13 '15 at 14:46
  • @skyking Yes, it does. Or do you have an example that produces different results for the same input? – poke Aug 13 '15 at 14:47
  • The original includes prompting for a key for example... – skyking Aug 13 '15 at 14:50
  • @skyking My code replaces the `if/else` part, as obviously requested by OP by their initial try to make it a single line in the first code excerpt. – poke Aug 13 '15 at 14:51
  • @skyking That was only so you could just copy and paste the code and see what it was doing. This is exactly what I wanted as an answer – SirParselot Aug 13 '15 at 14:52
  • Yes, the question has changed... – skyking Aug 13 '15 at 14:54
  • 2
    @skyking It was perfectly clear to me from the original text. The *“Here's what I have tried so far”* code shows how it should look like; with the replacement of `s` done in a single line. But OP’s code didn’t work (as made clear by the line afterwards which introduces the *“version which actually works“*), so he asked for how to do this correctly while having it still work. I can’t help it that you didn’t understand it but I did. And that also doesn’t invalidate my answer, so I have no idea why my answer is being downvoted when it is exactly what OP was asking for. – poke Aug 13 '15 at 15:00
  • @poke Wow I had never seen the translate function before. I want to write something just so I can use it lol – SirParselot Aug 13 '15 at 15:30
0

Given this simple test case

>>> from string import ascii_lowercase as letters
>>> s = 'this is a test with 2 numbers 55!'
>>> rot = 5

The following one-liner seems to do the trick

>>> ''.join(letters[(letters.index(i)+rot)%len(letters)] if i in letters else i for i in s)
'ymnx nx f yjxy bnym 2 szrgjwx 55!'
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
  • This does not take into account the keyed cipher case. Only the rotation case. There is a link in the question if you don't understand the keyed cipher. It's a nice explanation – SirParselot Aug 13 '15 at 14:40
0

This is just a quick golfing of your code (178 bytes):

rot=raw_input('Enter Rotation or Key: ').lower();s='abcdefghijklmnopqrstuvwxyz';print s[-int(rot):]+s[:-int(rot)]if rot.isdigit()else rot+reduce(lambda s,i:s.replace(i,''),rot,s)
Cyphase
  • 11,502
  • 2
  • 31
  • 32
  • I don’t get where you got the idea from that OP wanted to golf the code… – poke Aug 13 '15 at 14:52
  • @poke "I have a few lines of code ... and just for fun I am trying to condense them into one ...". Not exactly "golfing", I know, but pretty close. That said, I should probably go to sleep, so I could just be wrong :). – Cyphase Aug 13 '15 at 14:56
  • @Cyphase you condensed more than I was looking for but it still answers the question so +1 for that – SirParselot Aug 13 '15 at 14:59
0

The simplest one-liner you can have: s = rotify(s, rot)

s = 'abcdefghijklmnopqrstuvwxyz'
rot = raw_input('Enter Rotation or Key: ')
s = rotify(s, rot)
print s

All you need is a function rotify(), which you've already provided yourself in the question (I made few modifications from s = to return):

def rotify(s, rot):
    if rot.isdigit():
        return s[-int(rot):] + s[:-int(rot)]
    else:
        for i in rot.lower():
            s = s.replace(i,'')
        return rot.lower() + s

There's no need to force one-liners. You gain nothing, you lose readability.

Markus Meskanen
  • 19,939
  • 18
  • 80
  • 119
  • Where do you find the `rotify` function? – skyking Aug 13 '15 at 14:48
  • @skyking It's OP's original code from his question, turned into a function which returns a value instead of storing it into a variable `s` – Markus Meskanen Aug 13 '15 at 14:48
  • 3
    @SirParselot Why's that? I find this to be much better and readable than any other answer. Like you said yourself: "Here is the readable version which actually works" – Markus Meskanen Aug 13 '15 at 14:49
  • @MarkusMeskanen But then it doesn't minimize the number of lines if you get to keep the lines thats already there, does it? – skyking Aug 13 '15 at 14:51
  • 2
    @skyking "Minimize the number of lines"? What's this, a one-line-notepad? – Markus Meskanen Aug 13 '15 at 14:54
  • 4
    I agree that it's a stupid question. – skyking Aug 13 '15 at 14:57
  • It puts it on one line but I wanted the if else statement on one. I'm not completely inept when it comes to programming. I know how to make a function. – SirParselot Aug 13 '15 at 15:02
  • 1
    @SirParselot Then why ask this question in the first place? What you're trying to accomplish is insane. It's like wanting to have a bathroom with a laptop built-in to the wall: Why not just use a normal laptop which you can carry into the bathroom whenever you want? You're desperately seeking a way to mount a laptop into a solid wall, when the correct answer is not to do it in the first place. Don't condense the code, it's absolutely perfect right now. Not a single employer would like you to use the one-liners provided by others, rather than the multi-line solution you already have. – Markus Meskanen Aug 13 '15 at 15:06
  • @MarkusMeskanen for the simple reason of because I can. I'm not actually going to mount a laptop in the wall but I would at least like to know how. I am part of the human race which means I'm curious about the pointless things – SirParselot Aug 13 '15 at 15:10