2015-02-16 1 views
2

Я использую Scrapy lib. Я часто получаю списки с '\ t' и '\ n'.Python List Comprehendion: Элегантно вырезать и удалить пустые элементы в списке

Я пытаюсь использовать списки, чтобы разбить и удалить из них пустые элементы, но в конечном итоге с пустыми элементами.

Может ли кто-нибудь объяснить, как интерпретатор обрабатывает код? Кажется, что он проверяет пустые элементы, ТОГДА снимает и снова вставляет элементы в список.

Спасибо заранее!

# input 
char_list = ['', ' a','b', '\t'] 
print char_list 
char_list = [x.strip() for x in char_list if x!=''] 
print char_list 

# output 
['', ' a', 'b', '\t'] 
['a', 'b', ''] 

#DESIRED output 
['', ' a', 'b', '\t'] 
['a', 'b'] 

ответ

4

Обычно в этой ситуации я изменю его на 2 шага ... На первом этапе я делаю потенциально дорогостоящую обработку. На втором этапе я делаю фильтрацию. Первый шаг можно сделать с помощью выражения генератора, чтобы избежать ненужных списков:

char_list_stripped = (x.strip() for x in char_list) 
char_list = [x for x in char_list_stripped if x] 

В этом случае, это избавит вас от вызова x.strip в два раза столько раз, сколько вы на самом деле нужно (если вы упаковать все это в единое понимание). Это, вероятно, не огромные сбережения (вы, скорее всего, не заметите разницу в скорости). Но в более общем случае это может существенно повлиять в зависимости от того, сколько работы фактически влечет за собой обработка.

+0

Отлично. Спасибо за объяснение! – jsmiao

4
char_list = [x.strip() for x in char_list if x.strip()] 

что вы хотите удалить ненужные строки. x! = "" не удалять "\ t".

+0

Спасибо за ответ. Почему вы выполняете функцию strip() дважды? – jsmiao

+0

Просто хочу дать то, что вы хотите – amow

+1

Первая полоска дает требуемую полосу, вторая проверяет состояние, поэтому сначала будет работать только вторая полоса, это правда. – Niyojan

1

двойное понимание будет более эффективным, чем один понимание с двумя вызовами раздеться()

char_list = [ x for x in [ x.strip() for x in char_list ] if x ] 
+1

Генератор mgilsons еще эффективнее, но все еще может быть одним шагом 'char_list = [x for x in (x.strip() для x в char_list), если x]' –

1
>>> char_list = ['', ' a','b', '\t'] 
>>> filter(None, map(str.strip, char_list)) 
['a', 'b'] 
2

Это не очень хорошая практика, чтобы жёстко такие вещи в пауков. Посмотрите на Scrapy's built-in Item Loader и процессоры ввода/вывода. Попробуйте следующее в вашем РЕПЛЕ:

from scrapy.contrib.loader.processor import MapCompose 

def compact(s): 
    """ returns None if string is empty, otherwise string itself """ 
    return s if s else None 

char_list = ['', ' a','b', '\t'] 
MapCompose(unicode.strip, compact)(char_list) 
=> ['a', 'b'] 

MapCompose применяет заданные функции по каждому пункту в последовательности, каждая функция принимает один элемент в качестве аргумента, не исключая ни один из дальнейшей обработки.

Самого простой способ использовать этот подход в вашем items.py:

# -*- coding: utf-8 -*- 
import scrapy 
from scrapy.contrib.loader.processor import MapCompose 

def compact(s): 
    return s if s else None 

class MyItem(scrapy.Item): 
    my_field = scrapy.Field(
     input_processor=MapCompose(unicode.strip, compact) 
    ) 

И в parse_my_items обратного вызова вашего паука:

from scrapy.contrib.loader import ItemLoader 
from myproject.items import MyItem 

il = ItemLoader(item=MyItem()) 
il.add_value('my_field', char_list) 
my_item = il.load_item() 
yield my_item 
#=> {'my_field': [u'a', u'b']} 

Надеется, что это помогает!

Смежные вопросы