Home > Back-end >  How can I choose a specific intersection element in a list? TypeError: unhashed type: 'list
How can I choose a specific intersection element in a list? TypeError: unhashed type: 'list

Time:01-03

I would like to intersect two lists and print what they have in common. However, I would like to choose the specific element to intersect (e.g. [0] or [hockeymatch], [1], etc). With x[0] or y[1], my intention is not to select the entire line of the match, but to select only [hockeymatch]. I get this error:

TypeError: unhashable type: 'list'

In my code example, I would like to get this output:

'Seattle-Minnesota', 'NHL', '18:00'

So I would just like 'Seattle-Minnesota', 'NHL', '18:00', without:

  • without [1.33] and [62.0], because these numbers are different from [2.5] and [125.0] despite being contained in another 'Seattle-Minnesota', 'NHL', '18:00'
  • without 'Dallas-Arizona', 'NHL', '15:00' and 'Vancouver-Vegas', 'NHL', '20:00', because they are two different games from 'Seattle-Minnesota', 'NHL', '18:00'

IMPORTANT: This is just an example, but I will add more hockey matches. I don't want to manually print by setting only [('Seattle-Minnesota', 'NHL', '18:00')], but I would like to "AUTOMATICALLY" print any hockey match in common, even more than one match in common if there is one).

UPDATE: With x[0] or y[1], my intention is not to select the entire line of the match, but to select only [hockeymatch], for example ('Dallas-Arizona', 'NHL', '15:00 ')] or all of the other matches. I wanted a way to be able to select [hockeymatch], [number1], [number2] in the same line as the match.

In simple terms, I meant:

"considering that other hockey matches will be added in the future, look for one or more common matches (i.e. [hockeymatch]), but exclude from the intersection [number1] and [number2]"

Code:

#x = []
#x.append([[hockeymatch], [number1], [number2]])
x = [[[('Dallas-Arizona', 'NHL', '15:00')], [1.75], [87.5]],
     [('Seattle-Minnesota', 'NHL', '18:00')], [2.5], [125.0]]

#y = []
#y.append([[hockeymatch], [number1], [number2]])
y = [[[('Seattle-Minnesota', 'NHL', '18:00')], [1.33], [62.0]],
       [('Vancouver-Vegas', 'NHL', '20:00')], [0.50], [43.0]]

test = list(set(x[0]).intersection(y[0]))
print(test)

P.S: For greater clarity of the code I have added the comments of when I create the list and how I insert the elements with append

CodePudding user response:

#x = []
#x.append([[hockeymatch], [tournament], [number1], [number2]])
x = [[[('Dallas-Arizona', 'NHL', '15:00')], [1.75], [87.5]],
[('Seattle-Minnesota', 'NHL', '18:00')], [2.5], [125.0]]

#y = []
#y.append([[hockeymatch], [tournament], [number1], [number2]])
y = [[[('Seattle-Minnesota', 'NHL', '18:00')], [1.33], [62.0]],
[('Vancouver-Vegas', 'NHL', '20:00')], [0.50], [43.0]]

t1 = []
t2 = []

for i in range(len(x)):
     if i == 0:
          t1.append(tuple(x[i][0]))
     else:
          try:
               if len(x[i][0]) == 3:
                    t1.append(tuple(x[i]))
          except:
               pass

for i in range(len(y)):
     if i == 0:
          t2.append(tuple(y[i][0]))
     else:
          try:
               if len(y[i][0]) == 3:
                    t2.append(tuple(y[i]))
          except:
               pass

print(list((set(t1).intersection(set(t2)))))

You can simplify the code by using functions

x = [[[('Dallas-Arizona', 'NHL', '15:00')], [1.75], [87.5]],
[('Seattle-Minnesota', 'NHL', '18:00')], [2.5], [125.0]]


y = [[[('Seattle-Minnesota', 'NHL', '18:00')], [1.33], [62.0]],
[('Vancouver-Vegas', 'NHL', '20:00')], [0.50], [43.0]]

t1 = []
t2 = []

def matches(your_l, l_used):
     for i in range(len(l_used)):
          if i == 0:
               your_l.append(tuple(l_used[i][0]))
          else:
               try:
                    if len(l_used[i][0]) == 3:
                         your_l.append(tuple(l_used[i]))
               except:
                    pass

matches(t1, x)
matches(t2, y)

print(list((set(t1).intersection(set(t2)))))

CodePudding user response:

It should be:

list(set(x[1]).intersection(y[0][0]))
#[('Seattle-Minnesota', 'NHL', '18:00')]

Since x and y are nested lists. So, you were getting error when you were applying set() directly on 2D list.

TypeError: unhashable type: 'list'

CodePudding user response:

According to documentation:

A set is an unordered collection of distinct hashable objects. The objects have to be hashable so that finding, adding and removing elements can be done faster than looking at each individual element every time you perform these operations.

A list is not a hashable(/immutable) data-type. That means when you try to cast x[0] into a set, you need to make sure every element in x[0] is hashable (tuples, sets, etc not lists). You could change x[0] from a list to a tuple. (rounded parenthesis instead of square brackets) to make things work.

Also, it is generally a good idea to use tuples for data that does not need to be changed, at least in place.

x = [((('Dallas-Arizona', 'NHL', '15:00')), 1.75, 87.5), ...

CodePudding user response:

Mutable lists are causing you grief.

Let's use some immutable tuples!

from collections import namedtuple
from operator import itemgetter

Game = namedtuple("Game", "match, league, time, num1, num2")

x = [
    Game("Dallas-Arizona", "NHL", "15:00", 1.75, 87.5),
    Game("Seattle-Minnesota", "NHL", "18:00", 2.5, 125.0),
]
y = [
    Game("Seattle-Minnesota", "NHL", "18:00", 1.33, 62.0),
    Game("Vancouver-Vegas", "NHL", "20:00", 0.50, 43.0),
]


def getter(n: int, games: list[Game]):
    return list(map(itemgetter(n), games))


print(getter(0, x))
print(getter(0, y))

print("\nintersection:")
print(set(getter(0, x)) & set(getter(0, y)))
print("\nunion:")
print(set(getter(0, x)) | set(getter(0, y)))

output:

['Dallas-Arizona', 'Seattle-Minnesota']
['Seattle-Minnesota', 'Vancouver-Vegas']

intersection:
{'Seattle-Minnesota'}

union:
{'Seattle-Minnesota', 'Dallas-Arizona', 'Vancouver-Vegas'}

When displaying a set, the output will usually be a bit easier to read if you view the sorted( ... ) version of it.


Your question didn't give names to the business concepts, like what the 1st three fields denote or what the two numbers are all about.

If you like, you could define a 3-tuple and then define a bigger named tuple which includes it. Please feel free to post such source code if you test it and find it addresses your use case.

  • Related