목록 이해 vs. 필터 vs. 키 조회

8848 단어 python
저는 지난 주에 작업 작업을 하고 있었고 클래스 인스턴스 목록에서 클래스 인스턴스 하나를 필터링해야 했습니다. 어떻게 하든 이 작업을 한 번 또는 몇 번 수행하는 경우 이 속도는 그다지 중요하지 않습니다.

그러나 이 작업은 스크립트가 실행될 때마다 약 100,000회 수행되어야 하므로 이 경우 속도가 확실히 중요합니다.

먼저 filter() 를 사용하여 순진하게 시작했습니다. 그로 인해 10분 이상 기다려야 하는 경우 목록 이해가 더 빠르다는 것을 읽었습니다.

둘째, 목록 이해를 시도했습니다. 또한 10분 이상 기다렸다가 다시 포기했습니다.

마지막으로, 키는 내가 필터링해야 하는 항목이고 값은 클래스 인스턴스인 사전을 만드는 것이 효과가 있을 것이라고 생각했습니다. 이것이 답이었습니다! 초고속.

이제 내가 말하는 것의 몇 가지 예입니다.
Stuff 라는 클래스를 만듭니다.

class Stuff:
  def __init__ (self, letter):
    self.letter = letter
    super(Stuff, self). __init__ ()
  def __repr__ (self):
        return "<{} ({})>".format(self. __class__. __name__ , self.letter)

x = Stuff('s')
x
#> <Stuff (s)>
x.letter
#> 's'



클래스의 인스턴스 목록 만들기Stuff
import string

lst = []
for x in string.ascii_lowercase:
    lst.append(Stuff(x))
lst
#> [<Stuff (a)>, <Stuff (b)>, <Stuff (c)>, <Stuff (d)>, <Stuff (e)>, <Stuff (f)>, <Stuff (g)>, <Stuff (h)>, <Stuff (i)>, <Stuff (j)>, <Stuff (k)>, <Stuff (l)>, <Stuff (m)>, <Stuff (n)>, <Stuff (o)>, <Stuff (p)>, <Stuff (q)>, <Stuff (r)>, <Stuff (s)>, <Stuff (t)>, <Stuff (u)>, <Stuff (v)>, <Stuff (w)>, <Stuff (x)>, <Stuff (y)>, <Stuff (z)>]
len(lst)
#> 26



목록 이해: 목록 이해 방법을 수행한 방법입니다. 일부 속성이 일부 값과 일치하는 목록lst을 필터링합니다.

[x for x in lst if x.letter == 'f']
#> [<Stuff (f)>]



필터: 필터 방식을 이렇게 했습니다. 일부 속성이 일부 값과 일치하는 목록lst을 필터링합니다.

list(filter(lambda x: x.letter == 'f', lst))
#> [<Stuff (f)>]



그리고 여기에 사전 접근 방식이 있습니다. 여기에서 먼저 키가 각 인스턴스의 속성인 dict(zip())를 통해 사전을 만듭니다. 키로 조회할 수 있습니다.

이 접근 방식의 주요 차이점/단점은 사전이 중복 키를 허용하지 않기 때문에 키당 일치 항목이 하나만 있는 경우에만 작동한다는 것입니다.

lst_map = dict(zip([w.letter for w in lst], lst))
lst_map['f']
#> <Stuff (f)>



더 나은 방법은 키가 존재하지 않을 때 .get()가 발생하지 않도록 KeyError를 사용하는 것입니다.

lst_map.get('f')
#> <Stuff (f)>
lst_map.get('5')
#> (returns None)



타이밍은 어떻습니까?

from timeit import timeit
n = 100000
time_list_comp = timeit("[x for x in lst if x.letter == 'f']", number=n, globals=globals())
time_filter = timeit("list(filter(lambda x: x.letter == 'f', lst))", number=n, globals=globals())
time_dict = timeit("lst_map['f']", number=n, globals=globals())
time_dict_get = timeit("lst_map.get('f')", number=n, globals=globals())

round(time_list_comp, 3)
#> 0.088
round(time_filter, 3)
#> 0.134
round(time_dict, 3)
#> 0.002
round(time_dict_get, 3)
#> 0.003



대괄호 조회의 경우 목록 이해가 39배 느리고 필터가 59배 느립니다.
get() 조회의 경우 목록 이해가 26배 느리고 필터가 39배 느립니다.

좋은 웹페이지 즐겨찾기