3

I am a beginner in Python and am trying to solve the List Overlap problem on Practice Python.

I have written some code for solving this but the code seems to have a mind of its own. It works sometimes and at other times it just returns a blank. Where am I going wrong?

lista= map(int,input('Enter a list of numbers separated by spaces :').split())

listb= map(int,input('Enter another list of numbers separated by spaces :').split())

listc=[]

for item in lista:
    if item in listb:
        listc.append(item)


print(listc)

After running:

Enter a list of numbers separated by spaces :1 3 5
Enter another list of numbers separated by spaces :3 7 9
[] <-- unexpected result- I was hoping to see a new list with [3] in it.
ggorlen
  • 44,755
  • 7
  • 76
  • 106
Ani K
  • 33
  • 3
  • 4
    As far as I can tell it's because `map` returns an object, not a list. – melpomene Aug 04 '19 at 19:46
  • 4
    `lista` and `listb` ard not lists. In Python 3 `map` returns an object that can only be iterated once. If you want to test containment in `listb`, make it a list. Or, better still, a set. – khelwood Aug 04 '19 at 19:49
  • 2
    @khelwood I think you could post that comment as an answer. – melpomene Aug 04 '19 at 20:13
  • Change `lista= map(int,input('Enter a list of numbers separated by spaces :').split())` to `lista= list(map(int,input('Enter a list of numbers separated by spaces :').split()))`. Do the same thing for listb. @khelwood gives the reason. Or better yet:`lista= set(map(int,input('Enter a list of numbers separated by spaces :').split()))` because looking up an item in a set is a constant time operation independent of the set size. – Booboo Aug 04 '19 at 20:19
  • Possible duplicate of [Membership test for iterators](https://stackoverflow.com/questions/49089450/membership-test-for-iterators) – Georgy Aug 04 '19 at 20:32

2 Answers2

1

The strange behavior you're experiencing has to do with how the map function works in Python 3. You might be expecting that it returns a list as it does in Python 2 which can be repeatedly queried with the in keyword. In Python 3, however, map returns an iterator, which is an object that implements the __next__ method, enabling the mapped function to be applied lazily (but can only be traversed once). Using the in keyword on an iterator will exhaust it and harm accuracy of future in calls:

>>> map(int, ["1", "2", "3"])
<map object at 0x027FF5D0>
>>> it = map(int, ["1", "2", "3"])
>>> 1 in it
True
>>> 1 in it
False
>>> 1 in it
False

Had your example been something like 1 2 3 and 1 2 3, it'd appear to work because the iterator would find 1 in listb and pause, find 2 and pause, then find 3 and pause, exhausting both iterators together. But 1 3 5, 3 7 9 fails because the listb iterator is exhausted searching for 1 and returns false for any future in operations.

The solution is to explicitly convert the iterator returned by map into a list:

>>> list(map(int, ["1", "2", "3"]))
[1, 2, 3]

or use a list comprehension, which returns a list and effectively works as a map, applying a function to every element of the input list:

>>> [int(x) for x in ["1", "2", "3"]]
[1, 2, 3]

With this change, the code should work as expected. Note that making lista a list isn't strictly necessary since it's only traversed once (but the name suggests that you'd like it to be a list):

lista = list(map(int, input('Enter a list of numbers separated by spaces :').split()))
listb = list(map(int, input('Enter another list of numbers separated by spaces :').split())) 
#       ^^^^
listc = []

for item in lista:
    if item in listb:
        listc.append(item)

print(listc)

Sample run:

Enter a list of numbers separated by spaces: 1 3 5
Enter a list of numbers separated by spaces: 3 7 9
[3]

For further reading on iterables and iterators, see: What exactly are iterator, iterable, and iteration?.

Having gone through this, note that your code doesn't account for duplicates correctly, so you'll still fail the coding challenge you're attempting. See if you can manipulate your logic to check if the value isn't already in listc before adding. Once you've successfully finished the challenge using lists, try exploring the set data structure, as others have mentioned, which offers a semantic and efficient way of accomplishing intersection.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
0

Try the set function instead of a loop.

Edit: Change to overlapping instead of unique list values.

listc = set(lista) & set(listb)
Maeaex1
  • 703
  • 7
  • 36
  • Solves the problem, but is probably not the answer for the approach that is used in the question (using a loop). – Maeaex1 Aug 04 '19 at 20:26
  • This method generates numbers which are not overlapping. But using the set function is another way to approach this problem. – Ani K Aug 04 '19 at 21:50