5

I'm try to append text strings randomly so that instead of just having an output like

>>>david

I will end up having something like

>>>DaViD
>>>dAviD

the code i have right now is this

import random
import string

print "Name Year"
text_file = open("names.txt", "r")
for line in text_file:
    print line.strip()+"".join([random.choice(string.digits) for x in range(1, random.randint(1,9))])

and it outports this

>>>JOHN01361

I want that string to be somthing like

>>>jOhN01361
>>>john01361
>>>JOHN01361
>>>JoHn01361
Shawn Chin
  • 84,080
  • 19
  • 162
  • 191
user705260
  • 278
  • 1
  • 4
  • 13

4 Answers4

7

Well, your specification is actually to randomly uppercase characters, and if you were so inclined, you could achieve that with the following list comprehension:

import random

s = "..."
s = "".join( random.choice([k.upper(), k ]) for k in s )

but there may be nicer ways ...

Noon Silk
  • 54,084
  • 6
  • 88
  • 105
1

you probably want to do something like:

import random

lol = "lol apples"

def randomupper(c):
    if random.random() > 0.5:
        return c.upper()
    return c.lower()

lol =''.join(map(randomupper, lol))

EDIT:

As pointed out by Shawn Chin in the comments, this can be simplified to:

lol = "".join((c.upper(), c)[random() > 0.5] for c in lol)

Very cool and, but slower than using map.


EDIT 2:

running some timer tests, it seems that
"".join( random.choice([k.upper(), k ]) for k in s )
is over 5 times slower than the map method, can anyone confirm this?
Times are:

no map:        5.922078471303955
map:           4.248832001003303
random.choice: 25.282491881882898
Serdalis
  • 10,296
  • 2
  • 38
  • 58
  • Karl's suggestion to use `random.choice([k.upper(), k])` is more elegant, in my opinion. If I were to do it your way I'd use a lambda: `''.join(map(lambda c: random.random() > 0.5 and c.upper() or c, lol))`. – davidchambers Nov 05 '11 at 07:56
  • I try and avoid `lambda` as much as I can, specially in `map` because of its poor performance, his solution is defiantly more elegant, but I like having the option of changing the ratio if I prefer to have less / more caps. – Serdalis Nov 05 '11 at 08:21
  • 2
    Can be written without map or lambda : `"".join((c.upper(), c)[random() > 0.5] for c in lol)` – Shawn Chin Nov 05 '11 at 08:45
  • @ShawnChin oh wow I thought that statement only worked within lambdas, thanks for the comment, that's a good thing to know. – Serdalis Nov 05 '11 at 08:50
0

The following might be slightly more efficient than Nook's solution, also it doesn't rely on the text being lower-case to start with:

import random
txt = 'JOHN01361'
''.join(random.choice((x,y)) for x,y in zip(txt.upper(),txt.lower()))
Jonathan Livni
  • 101,334
  • 104
  • 266
  • 359
0

Timing different implementations just for fun:

#!/usr/bin/env python

import random

def f1(s):
    return ''.join(random.choice([x.upper(), x]) for x in s)

def f2(s):
    return ''.join((x.upper(), x)[random.randint(0, 1)] for x in s)

def f3(s):
    def randupper(c):
        return random.random() > 0.5 and c.upper() or c

    return ''.join(map(randupper, s))

def f4(s):
    return ''.join(random.random() > 0.5 and x.upper() or x for x in s)

if __name__ == '__main__':
    import timeit
    timethis = ['f1', 'f2', 'f3', 'f4']
    s = 'habia una vez... truz'
    for f in timethis:
        print '%s: %s' % (f,
                          timeit.repeat('%s(s)' % f, 'from __main__ import %s, s' % f,
                                        repeat=5, number=1000))

This are my times:

f1: [0.12144303321838379, 0.13189697265625, 0.13808107376098633, 0.11335396766662598, 0.11961007118225098]
f2: [0.22459602355957031, 0.23735499382019043, 0.19971895217895508, 0.2097780704498291, 0.22068285942077637]
f3: [0.044358015060424805, 0.051508903503417969, 0.045358896255493164, 0.047426939010620117, 0.042778968811035156]
f4: [0.04383397102355957, 0.039394140243530273, 0.039273977279663086, 0.045912027359008789, 0.039510011672973633]
Facundo Casco
  • 10,065
  • 8
  • 42
  • 63