6

Given a pattern and a string str, find if str follows the same pattern.

Here follows means a full match, such that there is a bijection between a letter in pattern and a non-empty word in str.

Examples: pattern = "abba", str = "dog cat cat dog" should return true; dog is a, cat is b and the words form the abba pattern. pattern = "abba", str = "dog cat cat fish" should return false; the string follows a abbc pattern instead.

My solution works in Python 2:

def wordPattern(self, pattern, str):
    s = pattern
    t = str.split()
    return map(s.find, s) == map(t.index, t)

But I am just wondering why this solution does not working in Python 3. There, the function will always return False when trying to test the above examples. Could anyone please give some advice?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
user3651247
  • 238
  • 1
  • 7
  • 19

1 Answers1

10

In Python 3, map() returns an iterator object, not a list. Equality testing between these objects won't work (equality is testing for identity, the exact same object in memory, instead).

Convert to lists explicitly:

def wordPattern(self, pattern, str):
    s = pattern
    t = str.split()
    return list(map(s.find, s)) == list(map(t.index, t))

or use list comprehensions:

def wordPattern(self, pattern, str):
    s = pattern
    t = str.split()
    return [s.find(c) for c in  s] == [t.index(w) for w in t]

or avoid creating lists altogether by comparing the zipped results with the all() function:

from operator import eq
from itertools import starmap, zip_longest

def wordPattern(self, pattern, str):
    s = pattern
    t = str.split()
    return all(starmap(eq, zip_longest(map(s.find, s), map(t.index, t))))

The latter short-circuits without having to make all comparisons if there is no match. In the spirit of keeping the functional style, I used itertools.starmap() to test for equality with the operator.eq() function. By using itertools.zip_longest() we make sure that we can detect the case where the pattern length and word count don't match.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • thanks for the corrections :) yours already tells the story to tell so mine is superflous. – Patrick Artner Feb 13 '18 at 13:36
  • I heard that `list1 == list2` comparisons short circuit too, is that right? see comment here https://stackoverflow.com/a/18410924/6260170 – Chris_Rands Feb 13 '18 at 13:37
  • 1
    @Chris_Rands: it does, but you first have to do two full iterations to *create the lists*. – Martijn Pieters Feb 13 '18 at 13:39
  • @MartijnPieters I think that the last solution only works if `s` and `t` have the same number of elements. Did I miss something? – luc Feb 13 '18 at 13:58
  • wordPattern(None, "abba", "dog cat cat dog dog") should return false and the last example returns true. You should check the number of elements first, i think – luc Feb 13 '18 at 13:59
  • The reason is that the `zip` function stops when iteration on one argument is done. additional elements on the other arguments are ignored – luc Feb 13 '18 at 14:00
  • @luc: yes, I know *why* :-P – Martijn Pieters Feb 13 '18 at 14:02
  • @MartijnPieters : with 622k of reputation, i imagine that you know it :-) Just explaining for any other wondering why. Thanks for edit and solution. – luc Feb 13 '18 at 14:04