문자열 목록에서 빈 문자열 제거


683

파이썬의 문자열 목록에서 빈 문자열을 모두 제거하고 싶습니다.

내 생각은 다음과 같습니다.

while '' in str_list:
    str_list.remove('')

이 작업을 수행하는 더 파이썬적인 방법이 있습니까?


45
@Ivo, 그 진술들 중 어느 것도 사실이 아닙니다. 반복 사용하는 목록을 사용해서는 안됩니다.를 사용하는 for x in list경우 while loop괜찮습니다. 루프는 빈 문자열이 더 이상 없을 때까지 빈 문자열을 제거한 다음 중지합니다. 나는 실제로 질문을 보지 않았지만 (제목 만) 가능성과 똑같은 루프로 대답했습니다! 메모리를 위해 이해력 또는 필터를 사용하지 않으려는 경우 매우 파이썬적인 솔루션입니다.
aaronasterling

4
그럼에도 불구하고 결코에 매우 유효한 점은 : 이상 반복하고 목록 변경
에드워드 루카

1
@EduardLuca 목록을 반복하는 것이 그것을 바꾸는 것이라면, 그것은 당신이 해야하는 것과 반대입니다. 그렇게하면 예기치 않은 동작이 발생하지 않는다는 점을주의해야합니다.
JFA

1
@EduardLuca, @JFA : 요점은 그가 어떤 목록을 반복하지 않는다는 것입니다. 그는 그가 어떤 형식으로 무언가를 썼다면 for var in list:여기에 글을 썼다 while const in list:. 어떤 것도 반복하지 않습니다. 조건이 거짓이 될 때까지 동일한 코드를 반복합니다.
Camion

답변:


1154

나는 사용할 것이다 filter:

str_list = filter(None, str_list)
str_list = filter(bool, str_list)
str_list = filter(len, str_list)
str_list = filter(lambda item: item, str_list)

파이썬 3은에서 반복자를 반환 filter하므로list()

str_list = list(filter(None, str_list))

11
당신이 경우 것이 성능을 누르면, itertool'들ifilter 도 faster-이다 >>> timeit('filter(None, str_list)', 'str_list=["a"]*1000', number=100000) 2.3468542098999023; >>> timeit('itertools.ifilter(None, str_list)', 'str_list=["a"]*1000', number=100000) 0.04442191123962402.
험프리 보가트

4
@cpburnz 매우 그렇습니다. 그러나 ifilter결과는 한 번에하지 않고 게으르게 평가 ifilter됩니다. 대부분의 경우 더 낫습니다. 사용하는 것은 흥미 filter여전히 빠를 포장보다 ifilterA의 list생각.
Humphrey Bogart

3
숫자 목록 에이 작업을 수행하면 0도 제거됩니다 (참고 : 처음 세 가지 방법 만 사용했습니다). 대체 방법이 필요합니다.
SnoringFrog

2
이것은 해결책이 얼마나 파이썬 적인지 (질문이 아닌) 속도가 아닌 속도에만 중점을 둡니다. List Comprehensions는 pythonic 솔루션이며, listcomp가 병목 현상이라는 프로파일 링이 입증 된 경우에만 필터를 사용해야합니다.
Tritium21

3
@ whoever-mentions-about-or-imply-Python-3, 답변을 수정하고 업데이트하십시오. 우리는이 질문을 받았을 때만 Python 2에 대해서만 논의하고 있었으며 심지어 Python 3조차 거의 2 년 동안 릴리스되었습니다. 그러나 파이썬 2와 3 결과를 모두 업데이트하십시오.
livibetter

237

리스트 이해력을 사용하는 것이 가장 파이썬적인 방법입니다.

>>> strings = ["first", "", "second"]
>>> [x for x in strings if x]
['first', 'second']

업데이트 된 데이터를 확인해야하는 다른 참조가 있으므로 목록을 내부에서 수정해야하는 경우 슬라이스 할당을 사용하십시오.

strings[:] = [x for x in strings if x]

16
쉽게 적응할 수 있기 때문에이 솔루션이 마음에 듭니다. 빈 문자열뿐만 아니라 공백 인 문자열을 제거 해야하는 경우 (예 :) [x for x in strings if x.strip()].
Bond

67

filter에는 실제로 다음과 같은 특별한 옵션이 있습니다.

filter(None, sequence)

False로 평가되는 모든 요소를 ​​필터링합니다. bool, len 등과 같은 실제 호출 가능 항목을 사용할 필요가 없습니다.

map (bool, ...)과 동일하게 빠릅니다.


5
이것은 실제로 파이썬 관용구입니다. 또한 내가 여전히 filter ()를 사용하는 유일한 시간이며, 목록 이해가 다른 곳을 대신했습니다.
kaleissin

24
>>> lstr = ['hello', '', ' ', 'world', ' ']
>>> lstr
['hello', '', ' ', 'world', ' ']

>>> ' '.join(lstr).split()
['hello', 'world']

>>> filter(None, lstr)
['hello', ' ', 'world', ' ']

시간 비교

>>> from timeit import timeit
>>> timeit('" ".join(lstr).split()', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
4.226747989654541
>>> timeit('filter(None, lstr)', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
3.0278358459472656

공지 사항 filter(None, lstr)공백으로 빈 문자열을 제거하지 않고는 ' ', 단지 멀리 프 i (prune) ''동안 ' '.join(lstr).split()제거합니다 모두.

filter()공백 문자열을 제거한 상태에서 사용하려면 시간이 더 걸립니다.

>>> timeit('filter(None, [l.replace(" ", "") for l in lstr])', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
18.101892948150635

단어의 문자열 사이에 공백이 있으면 작동하지 않습니다. 예를 들면 다음과 같습니다. [ 'hello world', '', 'hello', '']. >> [ 'helloworld', '', 'hello', '']리스트의 항목 안에 공백을 유지하고 다른 것을 제거하는 다른 솔루션이 있습니까?
Reihan_amn

공지 사항 filter(None, lstr)공백으로 빈 문자열을 제거하지 않습니다' ' 즉 빈 문자열이 아니기 때문에, 그래.
AMC

15

@ Ib33X의 답변은 훌륭합니다. 빈 문자열을 모두 제거하려면 스트립 후 제거하십시오. 스트립 방법도 사용해야합니다. 그렇지 않으면 공백이 있으면 빈 문자열도 반환합니다. ""도 해당 답변에도 유효합니다. 따라서 달성 할 수 있습니다.

strings = ["first", "", "second ", " "]
[x.strip() for x in strings if x.strip()]

이에 대한 답은입니다 ["first", "second"]. 방법을 대신
사용하려면 filter다음과 같이하십시오
list(filter(lambda item: item.strip(), strings)). 이것은 동일한 결과를 제공합니다.


12

x 대신에 빈 문자열을 제거하기 위해 if X! = ''을 사용합니다. 이처럼 :

str_list = [x for x in str_list if x != '']

이렇게하면 목록에 없음 데이터 형식이 유지됩니다. 또한 목록에 정수가 있고 그 중 하나가 0 인 경우에도 보존됩니다.

예를 들어

str_list = [None, '', 0, "Hi", '', "Hello"]
[x for x in str_list if x != '']
[None, 0, "Hi", "Hello"]

2
목록에 다른 유형이있는 경우 (없음 제외) 더 큰 문제가있을 수 있습니다.
Tritium21

어떤 타입? int 및 기타 숫자 유형, 문자열, 목록, 튜프, 세트 및 없음으로 시도했지만 아무런 문제가 없습니다. str 메소드를 지원하지 않는 사용자 정의 유형이 있으면 문제가 발생할 수 있음을 알 수 있습니다. 다른 것에 대해 걱정해야합니까?
thiruvenkadam

1
가있는 경우 str_list = [None, '', 0, "Hi", '', "Hello"]제대로 디자인되지 않은 응용 프로그램의 표시입니다. 당신은 하지 말았어야 같은 목록에 하나 이상의 인터페이스 (형)과 없음을.
Tritium21

3
DB에서 데이터를 검색 하시겠습니까? 자동 테스트를 수행하는 동안 함수에 대한 인수 목록?
thiruvenkadam 5

3
그것들은 보통 튜플입니다.
Tritium21

7

목록의 크기에 따라 새 목록을 만드는 대신 list.remove ()를 사용하는 것이 가장 효율적일 수 있습니다.

l = ["1", "", "3", ""]

while True:
  try:
    l.remove("")
  except ValueError:
    break

이것은 새로운 목록을 만들지 않는 장점이 있지만 매번 처음부터 검색해야한다는 단점이 있습니다. while '' in l위에서 제안한 것과 달리 검색 할 때마다 한 번만 검색하면됩니다 ''(확실히 최선을 유지할 수있는 방법이 있습니다) 두 가지 방법이지만 더 복잡합니다).


1
을 수행하여 목록을 제자리에서 편집 할 수 있습니다 ary[:] = [e for e in ary if e]. 훨씬 깨끗하고 제어 흐름에 예외를 사용하지 않습니다.
Krzysztof Karski

2
글쎄요, 그것은 실제로 "제자리에 있지 않습니다"-이것이 새로운 목록을 만들고 오래된 목록에 할당한다고 확신합니다.
Andrew Jaffe

제거 할 때마다 데이터 꼬리가 메모리에서 뒤섞이기 때문에 성능이 매우 떨어집니다. 한 번에 모두 제거하는 것이 좋습니다.
wim

7

공백을 문자열 안에 유지하려면 일부 접근 방식을 사용하여 실수로 제거 할 수 있습니다. 이 목록이 있다면

[ 'hello world', '', '', 'hello'] 원하는 것 [ 'hello world', 'hello']

먼저 모든 유형의 공백을 빈 문자열로 변환하도록 목록을 자릅니다.

space_to_empty = [x.strip() for x in _text_list]

그런 다음 목록에서 빈 문자열을 제거하십시오.

space_clean_list = [x for x in space_to_empty if x]

공백을 문자열 내에 유지하려면 일부 접근 방식을 사용하여 실수로 공백을 제거 할 수 있습니다. 이 접근 방식처럼?
AMC

고마워 친구, 그것은 약간의 변화와 함께 나를 위해 일했다. 즉,space_clean_list = [x.strip() for x in y if x.strip()]
무하마드 MEHRAN 칸 Attari

6

사용 filter:

newlist=filter(lambda x: len(x)>0, oldlist) 

지적한대로 필터를 사용하는 단점은 대안보다 속도가 느리다는 것입니다. 또한,lambda 일반적으로 비용이 많이 듭니다.

또는 가장 단순하고 가장 반복적 인 방법으로 갈 수 있습니다.

# I am assuming listtext is the original list containing (possibly) empty items
for item in listtext:
    if item:
        newlist.append(str(item))
# You can remove str() based on the content of your original list

이것은 가장 직관적 인 방법이며 적절한 시간 안에 수행합니다.


9
SO에 오신 것을 환영합니다. 당신은 무시되지 않았습니다. 당신은 명목없는 다운 보터의 공격을받지 않았습니다. 피드백을 받았습니다. 증폭 : 제안 된 필터에 대한 첫 번째 인수 는 선택한 답변에서 4 가지 솔루션 중 가장 lambda x: len(x)나쁜 것보다 나쁩니다 lambda x : x. 올바른 기능이 바람직하지만 충분하지는 않습니다. downvote 버튼 위에 커서를 놓으면 "이 답변은 유용하지 않습니다"라고 표시됩니다.
John Machin

5

Aziz Alto 가보고 한 것처럼 filter(None, lstr)공백이있는 빈 문자열을 제거하지는 않지만 ' 'lstr에 문자열 만 포함되어 있다고 확신하면 사용할 수 있습니다filter(str.strip, lstr)

>>> lstr = ['hello', '', ' ', 'world', ' ']
>>> lstr
['hello', '', ' ', 'world', ' ']
>>> ' '.join(lstr).split()
['hello', 'world']
>>> filter(str.strip, lstr)
['hello', 'world']

내 PC의 시간 비교

>>> from timeit import timeit
>>> timeit('" ".join(lstr).split()', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
3.356455087661743
>>> timeit('filter(str.strip, lstr)', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000)
5.276503801345825

''공백 ' '이 있는 문자열 을 제거 하고 비우는 가장 빠른 솔루션 은 남아 있습니다 ' '.join(lstr).split().

주석에보고 된 것처럼 문자열에 공백이 있으면 상황이 다릅니다.

>>> lstr = ['hello', '', ' ', 'world', '    ', 'see you']
>>> lstr
['hello', '', ' ', 'world', '    ', 'see you']
>>> ' '.join(lstr).split()
['hello', 'world', 'see', 'you']
>>> filter(str.strip, lstr)
['hello', 'world', 'see you']

당신은 것을 알 수 있습니다 filter(str.strip, lstr)거기에 공백이 포함 된 문자열을 유지하지만, ' '.join(lstr).split()이 문자열을 분할합니다.


1
문자열에 공백이없는 경우에만 작동합니다. 그렇지 않으면 해당 문자열도 분리합니다.
phillyslick

1
@BenPolinsky는 join솔루션 을보고 문자열을 공백으로 분할하지만 필터는 분할하지 않습니다. 답변을 개선했습니다.
Paolo Melchiorre

-1

최상의 답변을 요약하십시오.

1. 벗기지 않고 공허함 제거 :

즉, 모든 공백 문자열이 유지됩니다.

slist = list(filter(None, slist))

프로 :

  • 가장 단순한;
  • 가장 빠릅니다 (아래 벤치 마크 참조).

2. 스트리핑 후 빈 용기 제거하기 ...

2.a ... 문자열에 단어 사이에 공백이없는 경우 :

slist = ' '.join(slist).split()

프로 :

  • 작은 코드
  • 빠르지 만 (@ paolo-melchiorre 결과와 달리 메모리로 인해 큰 데이터 세트에서 가장 빠르지는 않습니다)

2.b ... 문자열에 단어 사이에 공백이 있으면?

slist = list(filter(str.strip, slist))

프로 :

  • 가장 빠른;
  • 코드의 이해 가능성.

2018 년 머신의 벤치 마크 :

## Build test-data
#
import random, string
nwords = 10000
maxlen = 30
null_ratio = 0.1
rnd = random.Random(0)                  # deterministic results
words = [' ' * rnd.randint(0, maxlen)
         if rnd.random() > (1 - null_ratio)
         else
         ''.join(random.choices(string.ascii_letters, k=rnd.randint(0, maxlen)))
         for _i in range(nwords)
        ]

## Test functions
#
def nostrip_filter(slist):
    return list(filter(None, slist))

def nostrip_comprehension(slist):
    return [s for s in slist if s]

def strip_filter(slist):
    return list(filter(str.strip, slist))

def strip_filter_map(slist): 
    return list(filter(None, map(str.strip, slist))) 

def strip_filter_comprehension(slist):  # waste memory
    return list(filter(None, [s.strip() for s in slist]))

def strip_filter_generator(slist):
    return list(filter(None, (s.strip() for s in slist)))

def strip_join_split(slist):  # words without(!) spaces
    return ' '.join(slist).split()

## Benchmarks
#
%timeit nostrip_filter(words)
142 µs ± 16.8 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit nostrip_comprehension(words)
263 µs ± 19.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_filter(words)
653 µs ± 37.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_filter_map(words)
642 µs ± 36 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_filter_comprehension(words)
693 µs ± 42.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_filter_generator(words)
750 µs ± 28.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit strip_join_split(words)
796 µs ± 103 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

s and s.strip()그냥 간단하게 할 수 있습니다 s.strip().
AMC

s and s.strip()우리가 완전히 filter(None, words)대답 하고 싶다면 대답 이 필요합니다 . 위의 x2 샘플 기능을 수정하고 x2 잘못된 기능을 삭제했습니다.
ankostis

-2

공백과 값이 조합 된 목록의 경우 간단한 목록 이해를 사용하십시오.

>>> s = ['I', 'am', 'a', '', 'great', ' ', '', '  ', 'person', '!!', 'Do', 'you', 'think', 'its', 'a', '', 'a', '', 'joke', '', ' ', '', '?', '', '', '', '?']

보시다시피이 목록에는 공백과 null 요소가 조합되어 있습니다. 스 니펫 사용하기-

>>> d = [x for x in s if x.strip()]
>>> d
>>> d = ['I', 'am', 'a', 'great', 'person', '!!', 'Do', 'you', 'think', 'its', 'a', 'a', 'joke', '?', '?']
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.