Keep largest duplicate value in list based on a particular member value

Viewed 20

I have this list and I am trying to

  • only keep one item for every unique item[0] and
  • the one item kept must have the highest value in item[3] For example, the item[0] [832] is repeated multiple times in the list ([832], ['G'], ['A'], [39]), ([832], ['G'], ['A'], [40]), ([832], ['G'], ['A'], [40]), ([832], ['G'], ['A'], [38]), ([832], ['G'], ['A'], [39]), ([832], ['G'], ['A'], [40]), ([832], ['G'], ['A'], [40]), ([832], ['G'], ['A'], [40])

I would like to only keep one ([832], ['G'], ['A'], [40]) value as it has the largest item[3]

For the case ([2792, 2810], ['C', 'C'], ['T', 'T'], [40, 40]) I would like to treat it as two separate cases ([2792], ['C'], ['T'], [40, 40]) and ([2810], ['C'], ['T'], [40])

my list:

[([832], ['G'], ['A'], [39]), ([2792], ['C'], ['T'], [39]), ([2810], ['C'], ['T'], [40]), ([586], ['G'], ['A'], [40]), ([586], ['G'], ['A'], [40]), ([832], ['G'], ['A'], [40]), ([2810], ['C'], ['T'], [40]), ([2792, 2810], ['C', 'C'], ['T', 'T'], [40, 40]), ([2730], ['A'], ['G'], [40]), ([4623, 4624], ['A', 'T'], ['G', 'C'], [29, 12]), ([2810], ['C'], ['T'], [40]), ([4687], ['T'], ['G'], [22]), ([2730], ['A'], ['G'], [40]), ([3493], ['G'], ['T'], [40]), ([2730], ['A'], ['G'], [40]), ([2810], ['C'], ['T'], [40]), ([832], ['G'], ['A'], [40]), ([444, 471], ['A', 'A'], ['T', 'T'], [10, 15]), ([2730], ['A'], ['G'], [40]), ([784], ['T'], ['A'], [27]), ([2730], ['A'], ['G'], [40]), ([2730], ['A'], ['G'], [40]), ([2792, 2810], ['C', 'C'], ['T', 'T'], [40, 40]), ([5373], ['T'], ['C'], [31]), ([3131], ['G'], ['A'], [40]), ([2730], ['A'], ['G'], [40]), ([2810], ['C'], ['T'], [40]), ([2792, 2810], ['C', 'C'], ['T', 'T'], [40, 40]), ([586], ['G'], ['A'], [40]), ([3578], ['A'], ['T'], [40]), ([2810], ['C'], ['T'], [40]), ([2730], ['A'], ['G'], [39]), ([832], ['G'], ['A'], [40]), ([2810], ['C'], ['T'], [40]), ([832], ['G'], ['A'], [38]), ([4248], ['T'], ['A'], [33]), ([832], ['G'], ['A'], [39]), ([2792], ['C'], ['T'], [40]), ([586], ['G'], ['A'], [40]), ([832], ['G'], ['A'], [40]), ([2730], ['A'], ['G'], [40]), ([2730], ['A'], ['G'], [40]), ([2730], ['A'], ['G'], [38]), ([2810], ['C'], ['T'], [40]), ([832], ['G'], ['A'], [40]), ([2730], ['A'], ['G'], [37]), ([4146, 4173], ['A', 'T'], ['T', 'G'], [33, 9]), ([99, 103], ['A', 'A'], ['C', 'C'], [24, 28]), ([99, 108], ['A', 'A'], ['C', 'C'], [19, 28]), ([882], ['T'], ['A'], [40]), ([2663], ['T'], ['A'], [23]), ([832], ['G'], ['A'], [40]), ([2792], ['C'], ['T'], [40])]
1 Answers

Since your own approach involved sorting the list, I assume that the order of the result list is not important. In this case, you can use e.g. a dict to map the key element to the item with the max value in index 3, and then just get the values from that dictionary.

max_v = {}
for t in lst:
    k = tuple(t[0])
    if k not in max_v or t[3] > max_v[k][3]:
        max_v[k] = t

res = list(max_v.values())

If order is important, then you could still use that as a preprocessing step, and then get only those elements from the list (in their original order) that match the value for their respective key in the dictionary. Since there are also exact duplicate elements, you will have to pop them from the dict as you go (or filter out the dupes first, but that's more involved since the items are not hashable).

res2 = [max_v.pop(tuple(t[0])) for t in lst if t == max_v.get(tuple(t[0]))]

Or another kind of sneaky way: Since dict preserves insertion order in newer version of Python, you could del the item from the dict if they are already in there, so a new item is inserted instead of replacing the old one, i.e.:

    if k not in max_v or t[3] > max_v[k][3]:
        if k in max_v:
            del max_v[k]
        max_v[k] = t
Related