Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to address current state of list comprehension in its if condition?

I would like to turn the loop over the items in L in following code:

L = [1,2,5,2,1,1,3,4]
L_unique = []
for item in L:
    if item not in L_unique: 
        L_unique.append(item)

to a list comprehension like:

L_unique = [ item for item in L if item not in ???self??? ]

Is this possible in Python? And if it is possible, how can it be done?


1 Answers

List comprehension actually makes an anonymous function then call it, but the list built will not be stored in local variable dictionary, but in the stack maintained in Python, so few Python level operations can obtain this list (gc is a crazy but feasible choice. Sorry for my exaggeration before, the solution using gc is attached at the end):

>>> [locals().copy() for i in range(3)]
[{'.0': <range_iterator at 0x207eeaca730>, 'i': 0},    # does not contain the built list
 {'.0': <range_iterator at 0x207eeaca730>, 'i': 1},
 {'.0': <range_iterator at 0x207eeaca730>, 'i': 2}]
>>> dis('[i for i in iterable]')
  1           0 LOAD_CONST               0 (<code object <listcomp> at 0x00000211FEAFD000, file "<dis>", line 1>)
              2 LOAD_CONST               1 ('<listcomp>')
              4 MAKE_FUNCTION            0
              6 LOAD_NAME                0 (iterable)
              8 GET_ITER
             10 CALL_FUNCTION            1
             12 RETURN_VALUE

Disassembly of <code object <listcomp> at 0x00000211FEAFD000, file "<dis>", line 1>:
  1           0 BUILD_LIST               0    # build an empty list and push it onto the stack
              2 LOAD_FAST                0 (.0)
        >>    4 FOR_ITER                 4 (to 14)
              6 STORE_FAST               1 (i)
              8 LOAD_FAST                1 (i)
             10 LIST_APPEND              2     # get the built list through stack and index
             12 JUMP_ABSOLUTE            2 (to 4)
        >>   14 RETURN_VALUE

For the example you provided, you can use list(dict.fromkeys(L)) to get the same results in Python 3.7+. Here I use dict instead of set because dict can preserve the insertion order:

>>> list(dict.fromkeys(L))
[1, 2, 5, 3, 4]

According to @KellyBundy , the current method I have found is to use gc.get_objects, but this operation is very expensive (because it collects more than 1000 objects) and I can't determine its accuracy:

>>> [item for item in L if item not in gc.get_objects(0)[-1]]
[1, 2, 5, 3, 4]

Making operations cheaper through caching:

>>> lst = None
>>> [item for item in L if item not in (lst := gc.get_objects(0)[-1] if lst is None else lst)]
[1, 2, 5, 3, 4]
like image 116
Mechanic Pig Avatar answered Oct 29 '25 21:10

Mechanic Pig



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!