-1

So I have got a

list = [(0, [2, 0, 4], 1), (3, [2, 0, 4], 2), (1, [3, 0, 4], 2), (2, [3, 0, 4], 2)] 

Its elements are tuples that include:

  1. An ID as its first element
  2. A list within that always includes three random integers
  3. A time

Assume that this list will not be empty. I am struggling to write code that compares each individual component of the tuple elements and appending to a new list depending on a set of criteria.

First criteria is the lists in the middle of each tuple element. I want to compare each tuple whose middle lists are the same, so in my list above comparing list[0] to list[1] and list[2] to list[3]. If there is a tuple with no duplicate list in the middle as any other tuples then append that tuple to a new empty list.

Then for the elements with the matching lists within the tuples I want to compare the time values of those tuples, if it is the lowest time value for the tuples with the matching middle lists then that tuple will be appended to the new empty list. However, if this value is the same for the tuples with the matching middle lists I then want to compare their IDs and pick the lowest ID value.

For the example list above the desired output would be [(0, [2, 0, 4], 1), (1, [3, 0, 4], 2)] because for the tuples with the matching list [2, 0, 4] the lowest value for time was 1 while for the tuples with matching list [3, 0, 4] and a matching value for time the lowest ID value was 1.

If there is anything needed to be clarified I will try my best to answer.

Bharel
  • 23,672
  • 5
  • 40
  • 80

1 Answers1

0

First, map the list according to the numbers in the middle, then take items from the mapping and append items according to your criteria:

from collections import defaultdict
input_ = [(0, [2, 0, 4], 1), (3, [2, 0, 4], 2), (1, [3, 0, 4], 2), (2, [3, 0, 4], 2)] 

mapping = defaultdict(list)

for item in input_:
    mapping[tuple(item[1])].append(item)

output = []

for value in mapping.values():
    if len(value) == 1:
        output.append(value[0])
        continue
    output.append(min(value, key=lambda x: (x[2], x[0])))

print(output)

Output:

[(0, [2, 0, 4], 1), (1, [3, 0, 4], 2)]
Bharel
  • 23,672
  • 5
  • 40
  • 80
  • 1
    Very nice answer! I personally would prefer a list comprehension for the output and no special exception for the case of `len(value) == 1`. Like this: `output = [min(value, key=lambda x: (x[2], x[0])) for value in mapping.values()]` – Oli May 23 '22 at 12:48
  • 1
    Some explanation: the dictionary keys are converted to tuples rather than using the lists directly because lists are not hashable - they are not hashable because they can be modified (they are "mutable"), whereas tuples are "immutable" and therefore can be hashed and safely used as dictionary keys. The `min(value, key=lambda x: (x[2], x[0]))` finds the tuple with the lowest time, and if times are equal then compares by ID - this takes advantage of how python does comparison between tuples, where the first elements are compared and if they are equal, the second elements are compared etc. – Oli May 23 '22 at 12:58
  • @Oli Thank you very much! I'll add the explanation later, you may edit the answer if you wish :-) Regarding the list comprehension, it's possible but I usually prefer the code to be a little more sparse. The few nanoseconds you save aren't going to make much of a difference so they shouldn't come at the cost of readability. There are plenty of ways to optimize this even further, but algorithmically it is O(n) and not O(n^2) like the deleted answer. – Bharel May 23 '22 at 13:59
  • @Oli Biggest optimization if you wonder would be switching the `lambda` to an `itemgetter(2,0)` initialized outside of the loop. Wanna do that? :-) You can compare the timing before and after and you'll notice quite a difference. – Bharel May 23 '22 at 14:02
  • I'm not too worried about performance, I just find it easier to read a list comprehension in this case. Just personal preference! For the purposes of readability, I think a lambda is probably better than `itemgetter`. – Oli May 23 '22 at 22:22
  • @Bharel I have now added this code to my main code but now I am getting a memoryerror, do you know how to fix that? – Miguel Valiente May 24 '22 at 00:44
  • How large is the list – Bharel May 24 '22 at 01:16