Title: Finding common elements of a list based on some criteria?
Tags: python;python-3.x;list
Question: The input is in form of a list of tuples,
left_corners = [((380, 456), 1), ((1129, 456), 2), ((354, 328), 3), ((1137, 325), 4)]
right_corners = [((784, 456), 1), ((1535, 456), 2), ((778, 328), 3)]
The common elements would be the ones which have the second element of the tuple as 1, 2, 3 so I would want the final representation to look like -
[(((380, 456), 1),((784, 456), 1)), (((1129, 456), 2),((1535, 456), 2)), (((354, 328), 3), ((778, 328), 3))]
I can't think of a solution without a few loops (looping over both the elements and appending the elements which have the same second element in a common list). Is there a more pythonic way? I am open to other representations of this in numpy or something too.
Assumptions:
We can assume both lists are sorted with the key being the second element of the list, but either left_corners or right_corners might have more elements than the other
Comment: In this example, if you just loop over the two lists together e.g. with `zip`, you would get pairs with the same second element. Is this always the case, or do you want to show an example that does not depend on this? And do you care about the ordering in the output?

Comment: @OlvinRoght This would include the unmatched `((1137, 325), 4)` at the end. The question is unclear about whether that is required or not.

Comment: @PyWalker2797 Please can you show the _whole_ output (without using `...`) in order to show whether the `((1137, 325), 4)` should be included somehow or omitted.

Comment: Because it is half seeming that all you need is `[t for t in zip(left_corners, right_corners)]` -- or there might be more to it.

Comment: it is not clear what the output is supposed to be, please state clearly how the output is defined

Comment: `list(map(tuple, map(itemgetter(1), groupby(sorted(left_corners + right_corners, key=itemgetter(1)), itemgetter(1)))))`. Does it look more pythonic? :D *[`groupby()`](https://docs.python.org/3/library/itertools.html#itertools.groupby), [`itemgetter()`](https://docs.python.org/3/library/operator.html#operator.itemgetter)*

Comment: @alaniwi, it's not the main problem of this code sample :D

Comment: Can we assume the "common" elements are sorted? Or are they random?

Comment: I have re-edited my post with some assumptions. Thanks for al your answers, I will check it!

Comment: Updated the output

Here is the accepted answer: If you use dictionaries, you could do something a bit more efficient
group_lists = {}
for corner in (left_corners+right_corners):
group_lists[corner[1]] = group_lists.get(corner[1], [])
group_lists[corner[1]].append(corner)
output = [group_lists[k] for k in group_lists]
And if you want your output to be a list of tuples instead of a list of lists you would just have to change that last line to
output = [tuple(group_lists[k]) for k in group_lists]

Here is another answer: How about a list comprehension?
a = [k for k in left_corners if k[1] in [1,2,3]] + [k for k in right_corners if k[1] in [1,2,3]]
output:
[((380, 456), 1), ((1129, 456), 2), ((354, 328), 3), ((784, 456), 1), ((1535, 456), 2), ((778, 328), 3)]
This is only valid, if the ordering is irrelevant. If it needs to have the order you can sort using a lambda function:
sorted(a, key=lambda x: x[1])
output:
[((380, 456), 1), ((784, 456), 1), ((1129, 456), 2), ((1535, 456), 2), ((354, 328), 3), ((778, 328), 3)]
Comment for this answer: Have you tested it? (Gives me an empty list.)
Comment for this answer: @JoKing it's still not giving me anything like the output shown in the question for the example inputs
Comment for this answer: the sorted version is the exact output

Here is another answer: first, second = (left_corners, right_corners) if len(left_corners) &gt; len(right_corners) else (right_corners, left_corners)
[(i, j) for i in first for j in second  if i[1] == j[1]]
I assumed that the second element (key to unify the tuples) can be anything not just 1, 2, 3
Another assumption is that the second element is sorted but can skip numbers for example, if this is not the case, then zip is the way to go.
left_corners = [(X, 1), (Y, 2), (Z, 3)]
right_corners = [(A, 1), (B, 3)]

Here is another answer: Maybe (not sure, as the problem is not very clearly stated) this is what you want:
good_corners = [ [ t for t in corners if t[1] in {1,2,3}] for corners in (left_corners, right_corners) ]
result = list(zip(*good_corners))
Comment for this answer: @OlvinRoght as the OP clarified, sorting is not needed at all - the lists are already sorted; so I changed my answer accordingly.
Comment for this answer: This might break on this case.. `right_corners = [((784, 456), 1), ((778, 328), 3)]`

Here is another answer: This worked pretty well for me
combined_list = list(zip(left_corners, right_corners))

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 5, 'CommentCount': 10, 'ContentLicense': 'CC BY-SA 4.0', 'CreationDate': '2020:00:06/16/20', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<python><python-3.x><list>', 'Title': 'Finding common elements of a list based on some criteria?', 'ViewCount': 70, 'id': 62417023, 'user_AboutMe': '<p>Apparently, this user prefers to keep an air of mystery about them.</p>\n', 'user_AccountId': 9197165.0, 'user_DisplayName': 'PyWalker2797', 'user_Reputation': 925.0, 'user_Views': 173.0, 'user_id': 12156208.0}}