Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How would you translate this from Perl to Python?

Tags:

python

perl

I've got a Perl function which takes a timestamp and returns either the unchanged timestamp (if it's never seen it before) or otherwise, it appends some letters to make it unique:

sub uniqify($) {
  my $timestamp = shift;

  state $last_ts = -1;
  state $next_letter = 'A';

  if ($timestamp == $last_ts) {
    $timestamp .= $next_letter++;
  } else {
    $last_ts = $timestamp;
    $next_letter = 'A';
  }

  return $timestamp;
}

So if you call it four times, with the values 1, 1, 1, and 2, it will return 1, then 1A, then 1B, then 2.

Note: It only ever gets called with ever-increasing timestamps, so it doesn't need to recall every one it's ever seen, just the last one.

Now I need to translate this function to Python. I've learned that I can replace the "state" variables with globals (yuck!) or perhaps attach them to the function as attributes, but neither of those is particularly elegant.

Also, Python doesn't have something like Perl's magic autoincrement, where if you "++" a variable whose value is "A", it becomes "B" -- or if it's "Z", it becomes "AA". So that's a curveball too.

I'm hacking together a solution, but it's really ugly and hard to read. Translating from Perl to Python is supposed to have the opposite effect, right? :) So I'm offering this as a challenge to SO users. Can you make it an elegant Python function?

like image 795
mike Avatar asked Mar 03 '09 00:03

mike


People also ask

How do I call a Perl script in Python?

Open your Python code in your Python editor of choice. Go to the line in the code where you want to run your Perl script. Type "pyth. RunPerl.

What is the difference between Python and Perl?

Answer: Python and Perl are high-level programming languages that were invented to serve different purposes. Perl was developed by Larry Wall as a Unix-based scripting language for making reports easily. Whereas Python was developed to offer code readability to its users for writing small and large programs.

Which language is better Perl or Python?

Python is also a great language for short scripts and web development, and it's generally better supported than Perl. While a great Perl programmer should be able to do anything a great Python programmer can do, it will be more difficult for them because fewer tools and utilities are available.


2 Answers

Look at this answer for a robust method to convert a number to an alphanumeric id

The code I present doesn't go from 'Z' to 'AA', instead goes to 'BA', but I suppose that doesn't matter, it still produces a unique id

from string import uppercase as up
import itertools

def to_base(q, alphabet):
    if q < 0: raise ValueError( "must supply a positive integer" )
    l = len(alphabet)
    converted = []
    while q != 0:
        q, r = divmod(q, l)
        converted.insert(0, alphabet[r])
    return "".join(converted) or alphabet[0]

class TimestampUniqifier( object ):
    def __init__(self):
        self.last = ''
        self.counter = itertools.count()
    def __call__( self, str ):
        if str == self.last:
            suf = self.counter.next()
            return str + to_base( suf, up )
        else:
            self.last = str
            self.counter = itertools.count()
            return str            

timestamp_uniqify = TimestampUniqifier()

usage:

timestamp_uniqify('1')
'1'
timestamp_uniqify('1')
'1A'
timestamp_uniqify('1')
'1B'
timestamp_uniqify('1')
'1C'
timestamp_uniqify('2')
'2'
timestamp_uniqify('3')
'3'
timestamp_uniqify('3')
'3A'
timestamp_uniqify('3')
'3B'

You can call it maaaany times and it will still produce good results:

for i in range(100): print timestamp_uniqify('4')

4
4A
4B
4C
4D
4E
4F
4G
4H
4I
4J
4K
4L
4M
4N
4O
4P
4Q
4R
4S
4T
4U
4V
4W
4X
4Y
4Z
4BA
4BB
4BC
4BD
4BE
4BF
4BG
4BH
4BI
4BJ
4BK
4BL
4BM
4BN
4BO
4BP
4BQ
4BR
4BS
4BT
4BU
4BV
4BW
4BX
4BY
4BZ
4CA
4CB
4CC
4CD
4CE
4CF
4CG
4CH
4CI
4CJ
4CK
4CL
4CM
4CN
4CO
4CP
4CQ
4CR
4CS
4CT
4CU
4CV
4CW
4CX
4CY
4CZ
4DA
4DB
4DC
4DD
4DE
4DF
4DG
4DH
4DI
4DJ
4DK
4DL
4DM
4DN
4DO
4DP
4DQ
4DR
4DS
4DT
4DU
like image 107
hasen Avatar answered Sep 28 '22 16:09

hasen


Well, sorry to say, but you can't just do a direct translation from Perl to Python (including bit-for-bit Perlisms) and expect the outcome to be prettier. It won't be, it will be considerably uglier.

If you want the prettiness of Python you will need to use Python idioms instead.

Now for the question at hand:

from string import uppercase

class Uniquifier(object):

    def __init__(self):
        self.last_timestamp = None
        self.last_suffix = 0

    def uniquify(self, timestamp):
        if timestamp == self.last_timestamp:
            timestamp = '%s%s' % (timestamp,
                                  uppercase[self.last_suffix])
            self.last_suffix += 1
        else:
            self.last_suffix = 0
            self.timestamp = timestamp
        return timestamp

uniquifier = Uniquifier()
uniquifier.uniquify(a_timestamp)

Prettier? Maybe. More readable? Probably.

Edit (re comments): Yes this fails after Z, and I am altogether unhappy with this solution. So I won't fix it, but might offer something better, like using a number instead:

timestamp = '%s%s' % (timestamp,
                      self.last_suffix)

If it were me, I would do this:

import uuid

def uniquify(timestamp):
    return '%s-%s' % (timestamp, uuid.uuid4())

And just be happy.

like image 40
Ali Afshar Avatar answered Sep 28 '22 15:09

Ali Afshar