Home > Software design >  Why does it tell me I am comparing functions?
Why does it tell me I am comparing functions?

Time:06-16

I am doing a CodeWars kata (Strings mix) and am getting an error. I have written the following code:

def mix(s1, s2):
    whitelist = set('abcdefghijklmnopqrstuvwxyz')
    out = []
    s1 = ''.join(sorted((c for c in s1 if c in whitelist), key = lambda c: (-s1.count(c), c)))
    s2 = ''.join(sorted((c for c in s2 if c in whitelist), key = lambda c: (-s2.count(c), c)))
    groups = sorted(list(set(s1) | set(s2)), key = lambda c: (-max([s1.count(c), s2.count(c)]), lambda v: 1 if (s1.count(v) > s2.count(v)) else 2, c))
    
    for i in groups:
        if max([s1.count(i), s2.count(i)]) <= 1:
            continue
        if s1.count(i) == s2.count(i):
            out.append('=:'   i * s1.count(i))
            continue
        if s1.count(i) > s2.count(i):
            out.append('1:'   i * s1.count(i))
            continue
        else:
            out.append('2:'   i * s2.count(i))
    
    return '/'.join(out)

The goal of line 6 (groups = sorted...)is to order the different individual letters correctly according the the kata's description. I am using a lambda function to create keys for the sorted() method which return a tuple of three values:

  • the max number of letters (c) of the two strings, negated for reverse order
  • trying to prioritize s1 over s2 if they have equal count of letters
  • and finally alphabetical order if all else fails

I suggest reading the kata description if that didn't make sense. I am getting the error:

Traceback (most recent call last):
  File "/workspace/default/tests.py", line 5, in <module>
    test.assert_equals(mix("Are they here", "yes, they are here"), "2:eeeee/2:yy/=:hh/=:rr")
  File "/workspace/default/solution.py", line 6, in mix
    groups = sorted(list(set(s1) | set(s2)), key = lambda c: (-max([s1.count(c), s2.count(c)]), lambda v: 1 if (s1.count(v) > s2.count(v)) else 2, c))
TypeError: '<' not supported between instances of 'function' and 'function'

I am kinda confused why this is happening since I don't see how s1.count(v) and s2.count(v) could be functions?

If the way I am trying to order the letters is completely wrong I wouldn't mind some help btw.

CodePudding user response:

As mentioned by Barmar in the comments, the sorted function's second criteria for sorting when the first criteria does not distinguish between elements is to compare lambda functions to each other, not letters. The > sign in the Traceback is not referring to s1.count(v) > s2.count(v), but instead to the sorted function's attempt to compare the two based on this second criteria, which is by comparing one lambda function to another lambda function.

To properly distinguish between s1 and s2 and give priority to s2, your way does indeed work (while retaining only the ternary if statement without the lambda, and replacing v with c). We could prove it mathematically by splitting things up into cases, but I suspect that's not what you are looking for. But intuitively, it works since you are basically checking if the count of the current letter in s1 is the max count of that letter, and if it is, then you give it priority over those in s2 with the same count, since in those cases s2.count(c) > s1.count(c), so the letters that have max counts in s2 are given lower priority. For example, given s1 = "ttt" and s2="sss", both have the same count, so they are sorted by the second criteria. s1.count("t")>s2.count("t") is True so it gets a value of 1 (higher priority), while s1.count("s")>s2.count("s") is False so it gets a value of 2 (lower priority, since sorted sorts from smallest to largest by default).

Another way you could code line 6 with somewhat greater clarity I think (although its arguable), would be as follows:

groups = sorted(list(set(s1) | set(s2)), key=lambda letter: (max(s1.count(letter),s2.count(letter)),s1.count(letter)>s2.count(letter), -ord(letter.lower())),reverse=True)

The ord function is used to convert the letter to its ascii value and then take the negative of it, to basically get the alphabetical order criteria back which was ruined by setting reverse=True.

  • Related