Reputation:
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
What am I doing wrong?
Is there anything wrong with how I'm trying to solve the problem using functional programming?
Upvotes: 2
Views: 484
Reputation:
I'd xor 2 strings together using zip
:
l = [ord(s1) ^ ord(s2) for s1,s2 in zip(str1,str2)]
Upvotes: 4
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
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