Nguyen Nguyen - 6 months ago 25
Python Question

Rank lists based on their content similarity to the reference list

I have a bunch of lists, each with many

string
components.

I want to use each of these lists as reference, and rank the other lists based on their similarity to the reference list.

pyp1 = ['yaz', 'vur', 'mir', 'rim', 'kiss', 'pass', 'qash', 'topp', 'goz', 'trs1', 'tsne', 'tkn', 'kaz']

idx1 = ['yaz', 'avur', 'mir', 'riem', 'kiss', 'pass', 'sash', 'zopp', 'gop', 'trs1', 'tsne', 'tkn', 'kaz', 'lor', 'lah', 'many', 'cup']

myc2 = ['ayaz', 'aavur', 'amir', 'ariem', 'miss', 'pass', 'zash', 'zopp', 'gopa', 'trs1', 'tsne', 'tkn', 'kaz', 'lor', 'lah', 'many', 'cup', 'avenir']

mik1 = ['yaz', 'avur', 'mir', 'riem', 'kiss','gopa', 'trs1', 'tsne', 'tkn', 'kaz', 'ariem', 'miss', 'pass', 'naz']

zach1 = ['zopp', 'gop', 'trs1', 'tsne', 'tkn', 'kaz', 'many', 'may1', 'myc2']


Let's say if I use pyp1 as a reference, I want to rank remaining lists
(myc2, mik1, idx1, zach1)
based on how many same strings they have compared to the reference list.

How can I do it with new function? Help is appreciated.

Answer Source

If you are trying to rank them by the number of matches to your reference, then you could simply use sets to calculate the intersection of your reference lists with the other lists. The length of the intersection gives you the number of matches as follows:

pyp1 = ['yaz', 'vur', 'mir', 'rim', 'kiss', 'pass', 'qash', 'topp', 'goz', 'trs1', 'tsne', 'tkn', 'kaz']
idx1 = ['yaz', 'avur', 'mir', 'riem', 'kiss', 'pass', 'sash', 'zopp', 'gop', 'trs1', 'tsne', 'tkn', 'kaz', 'lor', 'lah', 'many', 'cup']
myc2 = ['ayaz', 'aavur', 'amir', 'ariem', 'miss', 'pass', 'zash', 'zopp', 'gopa', 'trs1', 'tsne', 'tkn', 'kaz', 'lor', 'lah', 'many', 'cup', 'avenir']
mik1 = ['yaz', 'avur', 'mir', 'riem', 'kiss','gopa', 'trs1', 'tsne', 'tkn', 'kaz', 'ariem', 'miss', 'pass', 'naz']
zach1 = ['zopp', 'gop', 'trs1', 'tsne', 'tkn', 'kaz', 'many', 'may1', 'myc2']  

def sort_by_matches(ref, lists):
    reference = set(ref)
    lists = [[len(reference.intersection(set(x))), x] for x in lists]

    for count, a_list in lists:
        print("Matches {} in {}".format(count, a_list))

sort_by_matches(pyp1, [idx1, myc2, mik1, zach1])

This would display:

Matches 8 in ['yaz', 'avur', 'mir', 'riem', 'kiss', 'pass', 'sash', 'zopp', 'gop', 'trs1', 'tsne', 'tkn', 'kaz', 'lor', 'lah', 'many', 'cup']
Matches 5 in ['ayaz', 'aavur', 'amir', 'ariem', 'miss', 'pass', 'zash', 'zopp', 'gopa', 'trs1', 'tsne', 'tkn', 'kaz', 'lor', 'lah', 'many', 'cup', 'avenir']
Matches 8 in ['yaz', 'avur', 'mir', 'riem', 'kiss', 'gopa', 'trs1', 'tsne', 'tkn', 'kaz', 'ariem', 'miss', 'pass', 'naz']
Matches 4 in ['zopp', 'gop', 'trs1', 'tsne', 'tkn', 'kaz', 'many', 'may1', 'myc2']

If you want the output sorted by rank, you could sort it first by the number of matches, and then by the length of the list (shortest first), as in the example, two entries match 8. e.g.

lists = sorted([[len(reference.intersection(set(x))), x] for x in lists], key=lambda x: (x[0], -len(x[1])), reverse=True)

This would then give you:

Matches 8 in ['yaz', 'avur', 'mir', 'riem', 'kiss', 'gopa', 'trs1', 'tsne', 'tkn', 'kaz', 'ariem', 'miss', 'pass', 'naz']
Matches 8 in ['yaz', 'avur', 'mir', 'riem', 'kiss', 'pass', 'sash', 'zopp', 'gop', 'trs1', 'tsne', 'tkn', 'kaz', 'lor', 'lah', 'many', 'cup']
Matches 5 in ['ayaz', 'aavur', 'amir', 'ariem', 'miss', 'pass', 'zash', 'zopp', 'gopa', 'trs1', 'tsne', 'tkn', 'kaz', 'lor', 'lah', 'many', 'cup', 'avenir']
Matches 4 in ['zopp', 'gop', 'trs1', 'tsne', 'tkn', 'kaz', 'many', 'may1', 'myc2']