5

I have trouble with some code. I want my code to compare 2 Lists contained in a List of multiple Lists but only one time each.

resultList = [
    ['Student1', ['Sport', 'History']],
    ['Student2', ['Math', 'Spanish']],
    ['Student3', ['French', 'History']],
    ['Student4', ['English', 'Sport']],
]

for list1 in resultList:
    for list2 in resultList:
        i = 0
        for subject in list1[1]:
            if subject in list2[1]:
                if list2[1].index(subject) >= list1[1].index(subject):
                    i+=1
                else:
                    i+=2
        print(list1[0] + ' - ' + list2[0] + ' : ' + str(i))

This prints :

Student1 - Student1 : 2
Student1 - Student2 : 0
Student1 - Student3 : 1
Student1 - Student4 : 1
Student2 - Student1 : 0
Student2 - Student2 : 2
Student2 - Student3 : 0
Student2 - Student4 : 0
Student3 - Student1 : 1
Student3 - Student2 : 0
Student3 - Student3 : 2
Student3 - Student4 : 0
Student4 - Student1 : 2
Student4 - Student2 : 0
Student4 - Student3 : 0
Student4 - Student4 : 2

And i would like this result :

Student1 - Student1 : 2
Student1 - Student2 : 0
Student1 - Student3 : 1
Student1 - Student4 : 1
Student2 - Student2 : 2
Student2 - Student3 : 0
Student2 - Student4 : 0
Student3 - Student3 : 2
Student3 - Student4 : 0
Student4 - Student4 : 2

Thanks you for your help !

0

6 Answers 6

4

I would either use itertools.combinations_with_replacement or itertools.combinations for that:

In [1]: resultList = [
   ...:     ['Student1', ['Sport', 'History']],
   ...:     ['Student2', ['Math', 'Spanish']],
   ...:     ['Student3', ['French', 'History']],
   ...:     ['Student4', ['English', 'Sport']],
   ...: ]
   ...:

In [2]: import itertools
In [3]: new_result = itertools.combinations_with_replacement(resultList, 2)
In [4]: for lists_tuple in new_result:
    ...:     list1, list2 = lists_tuple
    ...:     i = 0
    ...:     for subject in list1[1]:
    ...:         if subject in list2[1]:
    ...:             if list2[1].index(subject) >= list1[1].index(subject):
    ...:                 i+=1
    ...:             else:
    ...:                 i+=2
    ...:     print(list1[0] + ' - ' + list2[0] + ' : ' + str(i))
    ...:
    ...:
Student1 - Student1 : 2
Student1 - Student2 : 0
Student1 - Student3 : 1
Student1 - Student4 : 1
Student2 - Student2 : 2
Student2 - Student3 : 0
Student2 - Student4 : 0
Student3 - Student3 : 2
Student3 - Student4 : 0
Student4 - Student4 : 2

combinations

In case you decide you don't want to compare each list to itself (Student1 - Student1), change combinations_with_replacement to combinations and you will get comparisons between different elements of the list:

Student1 - Student2 : 0
Student1 - Student3 : 1
Student1 - Student4 : 1
Student2 - Student3 : 0
Student2 - Student4 : 0
Student3 - Student4 : 0
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks you, as a beginner it seems a bit hard so I went with @Proyag's solution.
No problem. itertools is a very useful module in Python, you can always try some of its methods.
2

The idea is similar to @yatu's answer, but rather than manually keep count, you can use enumerate, and iterate over only the part of list2 after the current index in list1. If you want to avoid 1-1 2-2 pairs, just use resultList[idx+1:] instead of resultList[idx:].

resultList = [                                                                                                                 
    ['Student1', ['Sport', 'History']],                                                                                        
    ['Student2', ['Math', 'Spanish']],                                                                                         
    ['Student3', ['French', 'History']],                                                                                       
    ['Student4', ['English', 'Sport']],                                                                                        
]                                                                                                                              

for idx, list1 in enumerate(resultList):                                                                                       
    for list2 in resultList[idx:]:                                                                                             
        i = 0                                                                                                                  
        for subject in list1[1]:                                                                                               
            if subject in list2[1]:                                                                                            
                if list2[1].index(subject) >= list1[1].index(subject):                                                         
                    i+=1                                                                                                       
                else:                                                                                                          
                    i+=2                                                                                                       
        print(list1[0] + ' - ' + list2[0] + ' : ' + str(i))

Comments

2

You can utilize set.intersection to compare the lists:

resultList = [
    ['Student1', ['Sport', 'History']],
    ['Student2', ['Math', 'Spanish']],
    ['Student3', ['French', 'History']],
    ['Student4', ['English', 'Sport']],
]

s = set()
for list1 in resultList:
    for list2 in resultList:
        i = tuple(sorted([list1[0], list2[0]]))
        if i in s:
            continue
        s.add(i)
        print(list1[0], list2[0], len(set(list1[1]).intersection(list2[1])))

Prints:

Student1 Student1 2
Student1 Student2 0
Student1 Student3 1
Student1 Student4 1
Student2 Student2 2
Student2 Student3 0
Student2 Student4 0
Student3 Student3 2
Student3 Student4 0
Student4 Student4 2

Comments

1

version with two modified lines and two new ones, compared to the original:

resultList = [
['Student1', ['Sport', 'History']],
['Student2', ['Math', 'Spanish']],
['Student3', ['French', 'History']],
['Student4', ['English', 'Sport']],
]

for index1 in range(0,len(resultList)):
    for index2 in range(index1, len(resultList)):
        i = 0
        list1 = resultList[index1]
        list2 = resultList[index2]
        for subject in list1[1]:
            if subject in list2[1]:
                if list2[1].index(subject) >= list1[1].index(subject):
                    i+=1
                else:
                    i+=2
        print(list1[0] + ' - ' + list2[0] + ' : ' + str(i))

1 Comment

Thanks for your help, I figured out that @Proyag's solution was very easier.
1

You should do it more clearly,

Just 2 loops for and just 3 lines :

for i in resultList:
    for j in resultList[resultList.index(i):]:
            print(str(i[0]) + '-' + str(j[0]) + ' : ' + str((np.isin(i[1], j[1]) == True).sum()))

Result :

Student1-Student1 : 2
Student1-Student2 : 0
Student1-Student3 : 1
Student1-Student4 : 1
Student2-Student2 : 2
Student2-Student3 : 0
Student2-Student4 : 0
Student3-Student3 : 2
Student3-Student4 : 0
Student4-Student4 : 2

Your welcome :)

2 Comments

However, numpy may be unavailable on the target system. It probably can be replaced with simple in construction inside in a list comprehension, like [x in j[1] for x in i[1]].
Yes you are totally right, if numpy is unavailable use in is great.
-1

I think, you should do it just more clearly :).

Maybe try this way, using OOP:

import itertools.combinations

class Student:
    def __init__(self, name, subjects):
        self.name = name
        self.subjects = subjects

    def compare_to(self, another_student):
        result = 0
        for subject_my in self.subjects:
            for subject_he in another_student.subjects:
                if self.subjects.index(subject_my) >= \   
                        another_student.subjects.index(subject_he):
                    result+=1
                else:
                    result+=2
       return result

resultList = [
    Student('Student1', ['Sport', 'History']),
    Student('Student2', ['Math', 'Spanish']),
    Student('Student3', ['French', 'History']),
    Student('Student4', ['English', 'Sport'])
    ]

for first, secound in itertools.combinations(resultList):
    print("{} - {} : {}".format(first.name, secound.name, first.compare_to(secound)))

I think, it should look cleaner and more readable :). Choice is yours of course. Clear code, will simplify your chance to catch whats going wrong.

2 Comments

Thanks a lot for your answer ! It is a very good way to do so.
My bad. I used combinations instead another itertools with repetition, limited to 2 elements. Anyway ... itertools.combinations_with_replacement(resultList, 2) if u change it, this would work good :)

Your Answer

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