ลบสตริงว่างออกจากรายการของสตริง


683

ฉันต้องการลบสตริงที่ว่างเปล่าทั้งหมดออกจากรายการของสตริงในไพ ธ อน

ความคิดของฉันมีลักษณะเช่นนี้:

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

มีวิธี pythonic เพิ่มเติมที่จะทำเช่นนี้?


45
@Ivo ข้อความเหล่านั้นไม่เป็นความจริง คุณไม่ควรแก้ไขรายการที่วนซ้ำโดยใช้for x in listหากคุณกำลังใช้งานอยู่while loopมันก็ใช้ได้ การวนซ้ำที่แสดงจะลบสตริงว่างจนกว่าจะไม่มีสตริงว่างแล้วหยุด ที่จริงฉันไม่ได้ดูที่คำถาม (แค่ชื่อ) แต่ฉันตอบด้วยวงเดียวที่แน่นอนเป็นไปได้! หากคุณไม่ต้องการใช้ความเข้าใจหรือตัวกรองเพื่อความจำ
aaronasterling

4
ยังคงเป็นจุดที่ถูกต้องมากที่จะไม่เปลี่ยนแปลงรายการที่คุณกำลังทำซ้ำมากกว่า :)
เอดูอาร์ Luca

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)

Python 3 ส่งคืนตัววนซ้ำจากfilterดังนั้นควรตัดคำในการเรียกlist()

str_list = list(filter(None, str_list))

11
หากคุณที่กดประสิทธิภาพitertool'sifilterแม้ 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.
Humphrey Bogart

4
@cpburnz จริงมาก อย่างไรก็ตามด้วยifilterผลลัพธ์ที่ได้รับการประเมินอย่างเกียจคร้านไม่ใช่ในครั้งเดียว - ฉันยืนยันว่าสำหรับกรณีส่วนใหญ่ifilterจะดีกว่า ที่น่าสนใจที่ใช้filterยังคงเป็นเร็วกว่าการตัดifilterในlistแต่
Humphrey Bogart

3
หากคุณทำสิ่งนี้กับรายการตัวเลขโปรดทราบว่าเลขศูนย์จะถูกลบออกด้วย (หมายเหตุ: ฉันใช้ 3 วิธีแรกเท่านั้น) ดังนั้นคุณจะต้องใช้วิธีอื่น
SnoringFrog

2
สิ่งนี้จะเน้นเฉพาะเรื่องความเร็วไม่ใช่วิธีการแก้ปัญหาแบบไพ ธ อน (คำถามที่ถาม) รายการความเข้าใจเป็นวิธีการแก้ปัญหาแบบไพ ธ อนและควรใช้ตัวกรองเฉพาะเมื่อการทำโปรไฟล์ได้พิสูจน์แล้วว่า listcomp เป็นคอขวด
Tritium21

3
@ whoever-mentions-about-or-imply-Python-3 โปรดแก้ไขและอัปเดตคำตอบ เรากำลังคุยกันถึงเรื่อง Python 2 เท่านั้นเมื่อมีการถามคำถามนี้แม้กระทั่ง Python 3 ก็เปิดตัวเกือบ 2 ปี แต่อย่าอัพเดตทั้ง Python 2 และ 3 ผลลัพธ์
livibetter

237

การใช้list comprehensionเป็นวิธี Pythonic ที่สุด:

>>> 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()]แต่สายที่เป็นเพียงช่องว่างตัวอย่างเช่น:
บอนด์

67

ตัวกรองมีตัวเลือกพิเศษสำหรับสิ่งนี้:

filter(None, sequence)

มันจะกรององค์ประกอบทั้งหมดที่ประเมินเป็นเท็จ ไม่จำเป็นต้องใช้ callable จริงที่นี่เช่น bool, len และอื่น ๆ

มันเร็วพอ ๆ กับแผนที่ (บูล, ... )


5
นี่คือสำนวนของหลามอันที่จริงแล้ว มันเป็นครั้งเดียวที่ฉันยังคงใช้ตัวกรอง () ความเข้าใจในรายการมีอยู่ในที่อื่น
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)ว่าไม่ได้ลบสตริงว่างที่มีช่องว่าง' 'แต่จะตัดออกไปเท่านั้น''ขณะที่' '.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 ฉันจะใช้ถ้า 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 รายการอื่น tupes ชุดและไม่มีและไม่มีปัญหาที่นั่น ฉันจะเห็นว่าหากมีประเภทที่กำหนดโดยผู้ใช้ที่ไม่สนับสนุนวิธีการ str อาจทำให้เกิดปัญหา ฉันควรจะกังวลเกี่ยวกับอื่น ๆ ?
thiruvenkadam

1
หากคุณมีstr_list = [None, '', 0, "Hi", '', "Hello"]มันเป็นสัญญาณของแอปพลิเคชันที่ออกแบบมาไม่ดี คุณไม่ควรมีมากกว่าหนึ่งอินเทอร์เฟซ (ชนิด) และไม่มีในรายการเดียวกัน
Tritium21

3
กำลังดึงข้อมูลจาก db หรือไม่ รายการข้อโต้แย้งสำหรับฟังก์ชั่นขณะทำการทดสอบอัตโนมัติ?
thiruvenkadam

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

ขอบคุณครับมันใช้ได้ผลกับฉันด้วยการเปลี่ยนแปลงเล็กน้อย iespace_clean_list = [x.strip() for x in y if x.strip()]
Muhammad Mehran Khan 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 คุณไม่ได้ถูกเพิกเฉย คุณยังไม่ได้ถูกโจมตีจากผู้ลงคะแนนเสียงใด ๆ คุณได้รับข้อเสนอแนะ การขยายภาพ: อาร์กิวเมนต์แรกที่คุณเสนอสำหรับตัวกรองนั้นแย่กว่าlambda x: len(x)ที่แย่กว่าlambda x : xซึ่งเป็นวิธีที่แย่ที่สุดของ 4 ตัวเลือกในคำตอบที่เลือก ต้องการการทำงานที่ถูกต้อง แต่ไม่เพียงพอ เลื่อนเคอร์เซอร์ไปที่ปุ่ม 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']

เปรียบเทียบเวลาบนพีซีของฉัน

>>> 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โซลูชันจะแบ่งสตริงด้วยช่องว่าง แต่ตัวกรองจะไม่ ขอบคุณสำหรับความคิดเห็นที่ฉันปรับปรุงคำตอบของฉัน
เปาโลเมล

-1

สรุปคำตอบที่ดีที่สุด:

1. กำจัด emtpties โดยไม่ต้องปอก:

นั่นคือสตริงพื้นที่ทั้งหมดจะถูกเก็บไว้:

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', '', ' ', '', '?', '', '', '', '?']

ดังนั้นคุณสามารถเห็นรายการนี้มีการรวมกันของช่องว่างและองค์ประกอบที่เป็นโมฆะ การใช้ตัวอย่าง -

>>> 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.