How to remove duplicates with different orders from a list?

Question:

I made a special triangle (or whatever they’re called). It works fine but a flaw is it prints out the same triangle in a different order. This is the code:

SpecialTriangles = []

for i in range(15):
    for j in range(15):
        for k in range(15):
            if i**2 + j**2 == k**2:
                if i**2 + 0 != k**2:
                    if 0 + j**2 != k**2:   
                        if 0 + 0 != k**2:
                            SpecialTriangles.append([i, j, k])

print(SpecialTriangles)

And this is what the output is:

[[3, 4, 5], [4, 3, 5], [5, 12, 13], [6, 8, 10], [8, 6, 10], [12, 5, 13]]

So I want this to print just one of a kind in ascending order so:

[[3, 4, 5], [5, 12, 13], [6, 8, 10]]
Asked By: anaveragenoobie

||

Answers:

You’re looking for itertools.combinations:

from itertools import combinations

for i, j, k in combinations(range(15), 3):
    # do your logic with i, j, k

Just as you requested, combinations() will give each possible triplet just once.

Answered By: joanis

Here is one possible way with itertools.combinations. iterools.combinations returns a generator with each combination exactly once, then you check if your condition fits.

import itertools

out = list(
    filter(
        lambda x: x[0]**2 + x[1]**2 == x[2]**2, itertools.combinations([*range(15)], 3)
    )
)
print(out)
[(3, 4, 5), (5, 12, 13), (6, 8, 10)]

If you don’t want to use filter, instead a list comprehension (due to readability) here is another way:

out = [x for x in itertools.combinations([*range(15)],3) if x[0]**2 + x[1]**2 == x[2]**2]
print(out)
Answered By: Rabinzel

As the other answers mention, you are looking for combinations of the three elements, i.e. collections of the three indexes irrespectively of their order.

As an alternative to leave your code more "explicit", you might order the triplet of indexes and append it only if they are not already in SpecialTriangles:

SpecialTriangles = []

for i in range(15):
    for j in range(15):
        for k in range(15):
            if (i**2 + j**2) == k**2:
                if (i**2 + 0) != k**2:
                    if (0 + j**2) != k**2:   
                        if (0 + 0) != k**2:
                            ordered_triplet = sorted([i, j, k])
                            if ordered_triplet not in SpecialTriangles:
                                SpecialTriangles.append(ordered_triplet)

print(SpecialTriangles)

Here’s the result:

[[3, 4, 5], [5, 12, 13], [6, 8, 10]]
Answered By: Luca Clissa

While the answer by joanis is correct and efficient, I think it would still be a good idea to understand how to avoid the duplicate values.

With each nested for loop, you are starting back at 1 again and looping through to 15. However you would have already checked the values up to whatever value the for loop above is on.

For example, say you are in the loop where i = 7, you would not need to start at k = 1 as the values for 1 have already been checked when i = 1 at the first iteration.

e.g. This code:

for i in range(3):
    for k in range(3):
        print(i, k)

Outputs:

0 0
0 1
0 2
1 0
1 1
1 2
2 0
2 1
2 2

And as you can see, when i = 1, you only need to check the values of k > 1 as the rest have already been checked (0 1 is the same as 1 0)

The improved code would therefore be:

for i in range(3):
    for k in range(i, 3):
        print(i, k)

Which outputs:

0 0
0 1
0 2
1 1
1 2
2 2

And these values will be unique

So in your case, the improved nested loop should be:

for i in range(15):
    for j in range(i, 15):
        for k in range(j, 15):

I know this was a lot of info for a fairly simple question, but it can hopefully get you thinking about how you can make your code more efficient in the future!

Answered By: Hobanator
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.