简体   繁体   中英

Remove unnecessary items from python list

I have a list of 8 unique tuples, each of size 2. From there I find all possible combinations of size 4. Now, I have a list of lists, and in each of the sublists I have exactly 4 tuples. Something like -

[[(1, 2), (4, 5), (223, 456), (111, 345)], [...], ...]

Where the main list maybe -

[(1, 2), (4, 5), (223, 456), (111, 345), (123, 4), (23, 89), (999, 888), (895, 569)]

These are actually co-ordinates of points in a 2D plane and I am dividing the 8 points in two sets of 4 each. So if I have a list of 4 points, it means I already have the other four points as well. So for every combination of 4 points I am trying to remove the other 4 points from the list.

The following works -

def generate_all_points(points, size):
    from itertools import combinations

    all_combinations = combinations(points, size)
    return (list(all_combinations))    

def generate_4points(points):

    all_4points = generate_all_points(points, 4)
    print (len(all_4points))
    print ("ALL POINTS -\t", points)
    for point_set in all_4points:

        to_remove = list(set(points).difference(set(point_set)))
        for item in all_4points:
            if (len(set(to_remove).difference(item)) == 0):
                all_4points.remove(item)

        print ("Main -\t", point_set, "\nTo Remove -\t", to_remove)
        #all_4points.remove(list(set(points).difference(set(point_set))))
    print (len(all_4points))

I tried using just the set.difference but it reorders the list items and thus I can't remove them directly. That I tried in the commented line. What I did was find the remaining 4 points from the 8, then if the length of the set difference of the 4 and any item in the list of combinations is zero, then that means together, both set of 4 points match up to the unique 8, thus I remove that particular item.

Is there a way to directly achieve this maybe in one or two lines without loops and such?

Thanks in advance.

A better solution is to avoid generating the unwanted combinations in the first place.

This is in fact rather easy, as combinations are generated in order. We just have to take the first half of them. There are 70 combinations of 4 points among 8 (8*7*6*5/(4*3*2)), so we just keep the first 35 ones.

A demonstration, using the numbers from 1 to 8 instead of tuples for readability:

from itertools import combinations, islice

l = [1, 2, 3, 4, 5, 6, 7, 8]

nb_combinations = 70
print(list(islice(combinations(l, 4), nb_combinations//2)))

Output:

[(1, 2, 3, 4), (1, 2, 3, 5), (1, 2, 3, 6), (1, 2, 3, 7), (1, 2, 3, 8), 
(1, 2, 4, 5), (1, 2, 4, 6), (1, 2, 4, 7), (1, 2, 4, 8), (1, 2, 5, 6), 
(1, 2, 5, 7), (1, 2, 5, 8), (1, 2, 6, 7), (1, 2, 6, 8), (1, 2, 7, 8),
(1, 3, 4, 5), (1, 3, 4, 6), (1, 3, 4, 7), (1, 3, 4, 8), (1, 3, 5, 6),
(1, 3, 5, 7), (1, 3, 5, 8), (1, 3, 6, 7), (1, 3, 6, 8), (1, 3, 7, 8),
(1, 4, 5, 6), (1, 4, 5, 7), (1, 4, 5, 8), (1, 4, 6, 7), (1, 4, 6, 8),
(1, 4, 7, 8), (1, 5, 6, 7), (1, 5, 6, 8), (1, 5, 7, 8), (1, 6, 7, 8)]

You can see that all of these 35 combinations contain the first value 1, so we are certain that none of them is the complementary of another one of this set.

So, your function could be written:

from itertools import combinations, islice

def generate_4points(points):
    # we only keep the first 35 combinations out of 70
    return list(islice(combinations(points, 4), 35))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM