2

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?

  • Any obvious improvements you can think of?(the improvements would have to adhere to the functional paradigm too -- I'm doing this as a thought exercise, not in any project).
3
  • 1
    Pass an initializer (3rd parameter) to reduce to specify the behavior when the iterable is empty. docs.python.org/2/library/functions.html#reduce Commented Nov 10, 2013 at 16:40
  • @uki What are the values of a_list and a_string? Commented Nov 10, 2013 at 16:47
  • @thefourtheye dummy values of a_list could be ["asdf", "asdfg", "qwer"] and a_string could be "qwer". Commented Nov 11, 2013 at 1:00

3 Answers 3

4

I'd xor 2 strings together using zip:

l = [ord(s1) ^ ord(s2) for s1,s2 in zip(str1,str2)]
Sign up to request clarification or add additional context in comments.

Comments

1

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 ""), "")

Comments

1

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', '']

Comments

Your Answer

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