3

Does anybody know of a more efficent way to extend a string, eg fred, to be the length of the string plaintext - so that fred would become fredfredf - than this?

# key='fred', msg='plaintext'?

def keypad(key, msg):
    while len(key) < len(msg):
        key += key
    key = key[:len(msg)]
    return key

5 Answers5

5

Use islice + cycle from itertools:

from itertools import islice, cycle

key = 'fred'
msg = 'plaintext'

print(''.join(islice(cycle(key), len(msg))))
# fredfredf
Austin
  • 25,759
  • 4
  • 25
  • 48
3

No import needed, creates as few things as possible. Might be better then Austins solution (no imports, longer sourcecode):

key='fred'
msg='plaintext'

def keypad(key, msg):
    lk = len(key)
    lm = len(msg) 
    return ''.join( [ key[idx%lk] for idx in range(lm) ] )

print(keypad(key,msg))
# fredfredf

Leveraging the modulo division on the key-text in combination with a list (.join() would convert the generator to a list internally anyway - so faster to use a list in the first place - cudos to @Austin's comment).

Advantage:

  • no imports
  • no string slicing
  • uses generator, so no intermediate string creations (just one at the end)
  • no overshooting to be sliced away

Suggested read:

List vs generator comprehension speed with join function for speed of join() for list vs generator

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
2
key='fred'
msg='plaintext'
key = key*(len(msg)//len(key) + 1) 
print(key[:len(msg)]) 
#fredfredf

Or

print((key*(len(msg)//len(key) + 1))[:len(msg)])
ComplicatedPhenomenon
  • 4,055
  • 2
  • 18
  • 45
0

Less good then Austins solution, but better then yours:

Your approach is inefficient because you

  • concat strings: the old one is destroyed and a new one created (over and over)
  • you double the length of your combined string on each iteration (might get huge overshoot)

It would be better to calculate how often key fits into msg and create only one resulting string (reducing the amount of created/destroyed strings) and also reducing the size of the resulting string.

key='fred'
msg='plaintext'

def keypad(key, msg):
    l=len(msg)               # store loally  so you do not call len twice on it
    mult = l//len(key) + 1
    return (key*mult)[:l]    # overshoots maximally by len(k)-1 characters

print(keypad(key,msg))

Strings created for:

key = "1234"
msg = "1234567890123456789"

we create

"12341234"                         # you, created, thrown away
"1234123412341234"                 # you, created, thrown away
"12341234123412341234123412341234" # you

"12341234123412341234"             # me
Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
0
  • You can use divmod to compute the number of full repetitions needed, and the number of extra characters.
   def keypad(key, msg):
     wanted = len(msg)
     a, b = divmod(wanted, len(key))
     return key * a + key[:b]

or

To repeat a string until it's at least as long as the length you want.

  • You calculate the appropriate number of repeats and put it on the right-hand side of that multiplication operator.

  • Then, you can trim it to the exact length you want with an array slice:

   def keypad(key, msg):
     length = len(msg)
     return (key * (int(length/len(key))+1))[:length]
ParthS007
  • 2,581
  • 1
  • 22
  • 37