user277465
user277465

Reputation:

Python functional programming self-exercise

I realise that using a functional paradigm everywhere does not always result in very readable code -- the code segment below is something I'm doing just as an exercise. What I'm trying to do is as follows :-

Given a list of strings(L) and a string(S) I need to find L[i]^S. If S exists in L, don't xor the strings together. L[i]^S would mean xoring the bytes in the same position with each other.

This is how I proceeded to solve the problem. I tried to break it down to its simplest form - i.e. xoring of two characters. If one of the inputs wouldn't be a character, I return a "".(I couldn't think of a better way to do this).

xor_char   = lambda x, y: (chr(ord(x) ^ ord(y)) if x and y else "")
assert xor_char(None, "a") == ""
assert xor_char("a", " ")  == "A"

Next, I try to write some code to xor the strings together.

from operator import add
xor_string = lambda string_one, string_two: reduce(add, (map(xor_char, string_one, string_two) if string_one != string_two else ""))
assert xor_string("asdf", "asdfg") == "\x00\x00\x00\x00"
assert xor_string("asdf", "    ")  == "ASDF"

Then, finally I try to perform this on a list of strings and a string.

xor_list_string = lambda l, s: map(xor_string, l, [s]*len(l))
print xor_list_string(a_list, a_string)

I get an error as follows on running the above line :-

Traceback (most recent call last):
  File "2.py", line 26, in <module>
    main()
  File "2.py", line 23, in main
    analyze(all_lines, all_lines[-1])
  File "2.py", line 18, in analyze
    print xor_list_string(a_list, a_string)
  File "2.py", line 17, in <lambda>
    xor_list_string = lambda l, s: map(xor_string, l, [s]*len(l))
  File "2.py", line 11, in <lambda>
    xor_string = lambda string_one, string_two: reduce(add, (map(xor_char, string_one, string_two) if string_one != string_two else ""))
TypeError: reduce() of empty sequence with no initial value

Upvotes: 2

Views: 484

Answers (3)

user1301404
user1301404

Reputation:

I'd xor 2 strings together using zip:

l = [ord(s1) ^ ord(s2) for s1,s2 in zip(str1,str2)]

Upvotes: 4

Gening D.
Gening D.

Reputation: 423

Ok, is far as i understand you need to each string l in list of strings L to be xored with string b if there are not equal. You can use list comprehension for that:

In [1]: L = ['a', 'b', 'c', 'd', 'e', 'f']
In [2]: S = 'c'
In [3]: [ chr( ord(l) ^ ord(S)) if l is not S else S for l in L]
Out[3]: ['\x02', '\x01', 'c', '\x07', '\x06', '\x05']

We are using for l in L to iterate through L list, then we are checking if l element is equal to S ( if l is not S else S ) and if that works we doing xor-ing part.

Ok i've played around with your code. Problem with generator inside reduce. It gives you empty list in case strings are identical. You can fix that by moving if in to lambda instead of reduce. Like this:

a_list = [ 'as', 'qwe', 'vcs', 'ase', 'wsc', 'ase', 'sa' ]
a_string = 'sa'

xor_char   = lambda x, y: (chr(ord(x) ^ ord(y)) if x and y else "")
assert xor_char(None, "a") == ""
assert xor_char("a", " ")  == "A"

from operator import add
xor_string = lambda string_one, string_two: reduce(add, map(xor_char, string_one, string_two)) if string_one != string_two else ''
assert xor_string("asdf", "asdfg") == "\x00\x00\x00\x00"
assert xor_string("asdf", "    ")  == "ASDF"

xor_list_string = lambda l, s: map(xor_string, l, [s]*len(l))
print xor_list_string(a_list, a_string)

Output:

['\x12\x12', '\x02\x16', '\x05\x02', '\x12\x12', '\x04\x12', '\x12\x12', '']

Upvotes: 1

thefourtheye
thefourtheye

Reputation: 239473

It is always good to pass the initializer to reduce like this

reduce(add, (map(xor_char, string_one, string_two) if string_one != string_two else ""), "")

Upvotes: 1

Related Questions