3

I am a beginner at programing and I'm trying to figure out how list methods work. I wrote a tiny string scrambler and decoder for exercise purposes.

import random
sliced = []
keyholder = []
scrambled = []
decoded = []

def string_slicer(string):
    i = 0
    while i < len(string):
        sliced.append(string[i])
        i += 1

def string_scrambler(string):
    string = string_slicer(string)
    a = 0
    while len(scrambled) != len(sliced):
        value = len(sliced) - 1
        key = random.randint(0,value)
        if key in keyholder:
            continue
        else:
            scrambled.append(sliced[key])
            keyholder.append(key)
        continue

def string_decoder():
    x = 0
    for item in keyholder:
        decoded.insert(keyholder[x], scrambled[x])
        x += 1

string_scrambler('merhaba')
string_decoder()

print sliced
print keyholder
print scrambled
print decoded

When i'm testing it the string_scrambler() works fine but the string_decoder() gives random results. Here are some examples:

C:\Python27\Exercises>python scrambler.py
['m', 'e', 'r', 'h', 'a', 'b', 'a']
[2, 6, 0, 1, 3, 5, 4]
['r', 'a', 'm', 'e', 'h', 'b', 'a']
['m', 'e', 'r', 'h', 'a', 'a', 'b']

C:\Python27\Exercises>python scrambler.py
['m', 'e', 'r', 'h', 'a', 'b', 'a']
[4, 5, 1, 0, 3, 2, 6]
['a', 'b', 'e', 'm', 'h', 'r', 'a']
['m', 'a', 'r', 'e', 'h', 'b', 'a']

C:\Python27\Exercises>python scrambler.py
['m', 'e', 'r', 'h', 'a', 'b', 'a']
[1, 4, 5, 2, 3, 0, 6]
['e', 'a', 'b', 'r', 'h', 'm', 'a']
['m', 'e', 'a', 'r', 'h', 'b', 'a']

I think trying to add some items in an empty list with .insert method may cause this problem. But i can't figure out exactly why.

2 Answers 2

2

Note that a lot of your functions aren't necessary at all.

>>> list("some string")
["s", "o", "m", "e", " ", "s", "t", "r", "i", "n", "g"]`
# just like your `string_slicer` function.

Notably the problem with your approach is that you might try to do, for instance:

>>> lst = []
>>> lst.insert("after", 3)
>>> lst.insert("before", 2)
>>> lst
["after", "before"]

Since the list is initially length zero, inserting past the end point just sends it to the end of the list. Even though 3 is a more distant index than 2, it doesn't order correctly since essentially you've done

lst.append("after")
lst.append("before")

Instead, you could do something like:

scrambled = [''] * len(sliced)
# build a list of the same length as the cleartext sliced string

for idx, dest in enumerate(keyholder):
    scrambled[dest] = sliced[idx]

Then to descramble, do the opposite

deciphered = [''] * len(scrambled)
for idx, dest in enumerate(keyholder):
    deciphered[idx] = scrambled[dest]

The full solution I'd use, including some other tricks, is:

import random

def make_key(lst):
    return random.shuffle(range(len(lst)))

def scramble(lst, key):
    result = [''] * len(lst)
    for idx, dst in enumerate(key):
        result[dst] = lst[idx]
    return result

def unscramble(scrambled, key):
    return [scrambled[idx] for idx in key]

s = "merhaba"
key = make_key(list(s))

scrambled = scramble(list(s), key)
deciphered = unscramble(scrambled, key)

print(list(s))
print(key)
print(scrambled)
print(deciphered)

N.B. this removes every single list method you were trying to learn in the first place! You should notice this, because it's indicative of the fact that list methods are slow (with the exception of append and pop), and you should probably avoid using them if another equally-readable solution exists.

Sign up to request clarification or add additional context in comments.

Comments

-1

I think it's better to use not list as a data structure for decoded. I'd use dict as a temporary variable, here is my version of string_decoder:

_decoded = dict()  # changed

def string_decoder():
    x = 0
    for item in keyholder:
        _decoded[keyholder[x]] = scrambled[x]  #changed
        x += 1

    return [value for key, value in sorted(_decoded.items())]  #changed

decoded = string_decoder()

BTW, you have issues with list.insert() because you insert values to a list to the position which is absent, e.g. adding 4th item to a list of 2 elements.

Example of the behavior:

>>> decoded = []
>>> decoded.insert(100, 'b')
>>['b']
>>> decoded.insert(99, 'a')
>>> decoded
['b', 'a']  # according to your code, you expect ['a', 'b'] because 99 is less than 100, but the list has not enough entries. So, the item is just appended to the end

3 Comments

why? I mean since the key will always be a number corresponding to an index, I don't see any reason not to simply use indexes.
@AdamSmith I just edited my answer with the code sample.
Huh? This didn't address my comment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.