미적 측면과 성능 측면에서 조건부에 따라 항목 목록을 여러 목록으로 분할하는 가장 좋은 방법은 무엇입니까? 다음과 같습니다.
good = [x for x in mylist if x in goodvals]
bad = [x for x in mylist if x not in goodvals]
더 우아한 방법이 있습니까?
업데이트 : 여기에 내가하려는 일을 더 잘 설명하기위한 실제 사용 사례가 있습니다.
# files looks like: [ ('file1.jpg', 33L, '.jpg'), ('file2.avi', 999L, '.avi'), ... ]
IMAGE_TYPES = ('.jpg','.jpeg','.gif','.bmp','.png')
images = [f for f in files if f[2].lower() in IMAGE_TYPES]
anims = [f for f in files if f[2].lower() not in IMAGE_TYPES]
답변
good = [x for x in mylist if x in goodvals] bad = [x for x in mylist if x not in goodvals]
더 우아한 방법이 있습니까?
이 코드는 완벽하게 읽을 수 있으며 매우 명확합니다!
# files looks like: [ ('file1.jpg', 33L, '.jpg'), ('file2.avi', 999L, '.avi'), ... ]
IMAGE_TYPES = ('.jpg','.jpeg','.gif','.bmp','.png')
images = [f for f in files if f[2].lower() in IMAGE_TYPES]
anims = [f for f in files if f[2].lower() not in IMAGE_TYPES]
다시, 이것은 괜찮습니다!
세트를 사용하면 약간의 성능 향상이있을 수 있지만 사소한 차이가 있으므로 목록 이해가 훨씬 쉬워지고 순서가 엉망이되어 복제본이 제거되는 것에 대해 걱정할 필요가 없습니다.
사실, 나는 다른 단계 “뒤로”가서 간단한 for 루프를 사용할 수 있습니다.
images, anims = [], []
for f in files:
if f.lower() in IMAGE_TYPES:
images.append(f)
else:
anims.append(f)
목록 이해 또는 사용 set()
은 다른 검사 또는 다른 비트를 추가해야 할 때까지 괜찮습니다 .0 바이트 jpeg를 모두 제거하려면 다음과 같이 추가하십시오.
if f[1] == 0:
continue
답변
good, bad = [], []
for x in mylist:
(bad, good)[x in goodvals].append(x)
답변
게으른 반복자 접근 방식은 다음과 같습니다.
from itertools import tee
def split_on_condition(seq, condition):
l1, l2 = tee((condition(item), item) for item in seq)
return (i for p, i in l1 if p), (i for p, i in l2 if not p)
항목 당 한 번 조건을 평가하고 두 개의 생성기를 반환하며, 먼저 조건이 참인 순서에서 값을 산출하고 다른 조건이 거짓 인 값을 산출합니다.
게으 르기 때문에 모든 반복자, 심지어 무한 반복자에서도 사용할 수 있습니다.
from itertools import count, islice
def is_prime(n):
return n > 1 and all(n % i for i in xrange(2, n))
primes, not_primes = split_on_condition(count(), is_prime)
print("First 10 primes", list(islice(primes, 10)))
print("First 10 non-primes", list(islice(not_primes, 10)))
일반적으로 비 게으른 목록 반환 방법이 더 낫지 만
def split_on_condition(seq, condition):
a, b = [], []
for item in seq:
(a if condition(item) else b).append(item)
return a, b
편집 : 키를 사용하여 항목을 다른 목록으로 나누는 더 구체적인 유스 케이스의 경우 다음과 같은 일반적인 기능이 있습니다.
DROP_VALUE = lambda _:_
def split_by_key(seq, resultmapping, keyfunc, default=DROP_VALUE):
"""Split a sequence into lists based on a key function.
seq - input sequence
resultmapping - a dictionary that maps from target lists to keys that go to that list
keyfunc - function to calculate the key of an input value
default - the target where items that don't have a corresponding key go, by default they are dropped
"""
result_lists = dict((key, []) for key in resultmapping)
appenders = dict((key, result_lists[target].append) for target, keys in resultmapping.items() for key in keys)
if default is not DROP_VALUE:
result_lists.setdefault(default, [])
default_action = result_lists[default].append
else:
default_action = DROP_VALUE
for item in seq:
appenders.get(keyfunc(item), default_action)(item)
return result_lists
용법:
def file_extension(f):
return f[2].lower()
split_files = split_by_key(files, {'images': IMAGE_TYPES}, keyfunc=file_extension, default='anims')
print split_files['images']
print split_files['anims']
답변
제안 된 모든 솔루션의 문제점은 필터링 기능을 두 번 스캔하고 적용한다는 것입니다. 다음과 같이 간단한 작은 기능을 만들었습니다.
def SplitIntoTwoLists(l, f):
a = []
b = []
for i in l:
if f(i):
a.append(i)
else:
b.append(i)
return (a,b)
그렇게하면 아무것도 처리하지 않고 코드를 반복하지 않습니다.
답변
내가 가져가 partition
출력 하위 시퀀스에서 상대 순서를 유지 하는 게으른 단일 패스 함수를 제안합니다 .
1. 요구 사항
요구 사항은 다음과 같다고 가정합니다.
- 요소의 상대적 순서 유지 (따라서 세트와 사전 없음)
- 모든 요소에 대해 조건을 한 번만 평가하십시오 (따라서 (
i
)filter
또는groupby
) - 두 시퀀스 중 하나의 지연 소비를 허용합니다 (사전 계산할 여유가 있다면 순진한 구현도 수용 가능할 것입니다)
2. split
도서관
내 partition
기능 (아래 소개) 및 기타 유사한 기능으로 작은 라이브러리로 만들었습니다.
PyPI를 통해 정상적으로 설치 가능합니다 :
pip install --user split
조건에 따라 목록 기반을 분할하려면 partition
function을 사용하십시오 .
>>> from split import partition
>>> files = [ ('file1.jpg', 33L, '.jpg'), ('file2.avi', 999L, '.avi') ]
>>> image_types = ('.jpg','.jpeg','.gif','.bmp','.png')
>>> images, other = partition(lambda f: f[-1] in image_types, files)
>>> list(images)
[('file1.jpg', 33L, '.jpg')]
>>> list(other)
[('file2.avi', 999L, '.avi')]
3. partition
기능 설명
내부적으로 우리는 한 번에 두 개의 서브 시퀀스를 구축해야하므로, 하나의 출력 시퀀스 만 소비하면 다른 하나의 시퀀스도 계산됩니다. 또한 사용자 요청 (상점 처리되었지만 아직 요청되지 않은 요소)간에 상태를 유지해야합니다. 상태를 유지하기 위해 두 개의 이중 끝 큐 ( deques
)를 사용합니다.
from collections import deque
SplitSeq
수업은 하우스 키핑을 담당합니다.
class SplitSeq:
def __init__(self, condition, sequence):
self.cond = condition
self.goods = deque([])
self.bads = deque([])
self.seq = iter(sequence)
마술은 그 .getNext()
방법으로 일어난다 . 그것은 거의 .next()
반복자와 비슷하지만 이번에는 원하는 요소를 지정할 수 있습니다. 장면 뒤에서 거부 된 요소를 버리지 않고 대신 두 개의 대기열 중 하나에 넣습니다.
def getNext(self, getGood=True):
if getGood:
these, those, cond = self.goods, self.bads, self.cond
else:
these, those, cond = self.bads, self.goods, lambda x: not self.cond(x)
if these:
return these.popleft()
else:
while 1: # exit on StopIteration
n = self.seq.next()
if cond(n):
return n
else:
those.append(n)
최종 사용자는 partition
기능 을 사용해야 합니다. 조건 함수와 시퀀스 ( map
또는 처럼 filter
)를 취하고 두 개의 생성기를 반환합니다. 첫 번째 생성기는 조건이 유지되는 요소의 하위 시퀀스를 작성하고 두 번째 생성기는 상보 하위 시퀀스를 작성합니다. 반복자와 생성기는 길거나 무한한 시퀀스의 지연 분할을 허용합니다.
def partition(condition, sequence):
cond = condition if condition else bool # evaluate as bool if condition == None
ss = SplitSeq(cond, sequence)
def goods():
while 1:
yield ss.getNext(getGood=True)
def bads():
while 1:
yield ss.getNext(getGood=False)
return goods(), bads()
미래에 부분 적용을 용이하게하기 위해 테스트 함수를 첫 번째 인수로 선택했습니다 (테스트 함수를 첫 번째 인수로 사용하는 방법 map
과 유사 함 filter
).
답변
나는 기본적으로 Anders의 접근 방식을 매우 좋아합니다. 다음은 분류기를 가장 먼저 (필터 구문과 일치시키기 위해) 배치하고 defaultdict (가져온 것으로 가정)를 사용하는 버전입니다.
def categorize(func, seq):
"""Return mapping from categories to lists
of categorized items.
"""
d = defaultdict(list)
for item in seq:
d[func(item)].append(item)
return d
답변
첫 번째 이동 (사전 편집) : 세트 사용 :
mylist = [1,2,3,4,5,6,7]
goodvals = [1,3,7,8,9]
myset = set(mylist)
goodset = set(goodvals)
print list(myset.intersection(goodset)) # [1, 3, 7]
print list(myset.difference(goodset)) # [2, 4, 5, 6]
가독성 (IMHO)과 성능 모두에 좋습니다.
두번째 이동 (post-OP-edit) :
좋은 확장명 목록을 세트로 작성하십시오.
IMAGE_TYPES = set(['.jpg','.jpeg','.gif','.bmp','.png'])
그러면 성능이 향상됩니다. 그렇지 않으면, 당신이 나에게 잘 보이는 것.