2012-08-01 53 views
2

Possible Duplicate:
Remove items from a list while iterating in Python的Python:元组的搜索列表,删除整个索引

我有一个相当嵌入列表,具体地说,它是元组的列表的列表。为了简化事情,整个列表是一个句子列表。在每个句子中,每个单词都被制成一个元组,其中包含有关该单词的信息。每个句子中的最后一个元组包含关于说话者的信息,但如果需要的话可以删除。

我想通过这些元组进行搜索,如果找到某个值,则删除整个句子。

这里是一个示例清单:

sentenceList = [[('the', 'det', '1|2|DET'), ('duck', 'n', '2|3|SUBJ'), ('xxx', 'unk', '3|0|ROOT'), ('*MOT', 373)], 
       [('yyy', 'unk', '1|0|ROOT'), ('*CHI', 375)], 
       [('what', 'pro', '1|2|OBJ'), ('happen-PAST', 'v', '2|0|ROOT'), ('to', 'prep', '3|2|JCT'), ('the', 'det', '4|5|DET'), ('duck', 'n', '5|3|POBJ'), ('*MOT', 378)], 
       [('boom', 'int', '1|0|ROOT'), ('*CHI', 379)]] 

如果一个句子中包含两种'xxx''yyy',我想删除整个句子。我试过的代码是:

wordList = ['xxx','yyy'] 
for sentence in sentenceList: 
    for wordTuple in sentence: 
     for entry in wordTuple: 
      if entry in wordList: 
       del sentence 

这应该删除整个句子,即:

[('the', 'det', '1|2|DET'), ('duck', 'n', '2|3|SUBJ'), ('xxx', 'unk', '3|0|ROOT'), ('*MOT', 373)], [('yyy', 'unk', '1|0|ROOT'), ('*CHI', 375)] 

然而,这段代码似乎并没有被完成的任务。任何想法如何解决它?谢谢!

+1

我猜测问题是你正在从列表中删除列表中的一个成员('sentenceList'),而你正在遍历列表。 [这个答案](http://stackoverflow.com/questions/1207406/remove-items-from-a-list-while-iterating-in-python)应该可以帮助你解决这个问题。 – 2012-08-01 19:35:52

+0

谢谢@SamMussmann!我遇到过,但不知道如何适应我的具体情况。 – 2012-08-01 19:42:58

+0

我已经为您的问题添加了该答案的改编答案。我希望这有帮助。 :-) – 2012-08-01 21:56:06

回答

1

当您用for迭代它时尝试修改列表是很危险的。你真正想要的是一个while循环:

contrived_data = [[(1, 1, 1), ('hello', 'bar')], [(222, 3, 4), ('norweigan', 'blue')], [('anthrax', 'ripple'), (42, 'life')]] 

looking_for = (1, 'life') 

index = 0 
while index < len(contrived_data): 
    for two_pull in contrived_data[index]: 
     for item in looking_for: 
      if item in two_pull: 
       print(contrived_data.pop(index)) 
       index -= 1 
       break # Only jumps out of the innermost loop 
    index += 1 

,并应比复制您的原始列表更大的数据集更有效。

+0

但是,这将如何工作的单词列表(或集),但?由于这只检查“1”,我怎么能改变它来检查一堆值? – 2012-08-01 20:04:07

+0

这也似乎抛出“IndexError:弹出索引超出范围。”难道我做错了什么? – 2012-08-01 20:22:34

+0

我在那里添加了另一个循环,以及适当的'break'。更新是否仍然会抛出异常?确保您的缩进级别在所有方面都是正确的。而且,如果它仍然中断,请发布您的更新代码,我会看看我能做些什么。 – 2012-08-01 21:24:38

2
wordList = set(('xxx','yyy')) 
for sentence in sentenceList[:]: 
    removed = False 
    for wordTuple in sentence: 
     for entry in wordTuple: 
      if entry in wordList: 
       sentenceList.remove(sentence) 
       removed = True 
       break 
      # end of if 
     # end for each entry 
     if removed: 
      break 
    # end for each word tuple 
# end for each sentence 

注:

  • 遍历列表的(浅)的副本,以避免从修改你穿越
  • 从列表中删除的对象集合出现的错误,而不是简单地从本地命名空间
  • 删除变量名,这是效率不高的大型数据集
+0

一个集合对于'wordList'来说是一个更好的数据结构。 – mgilson 2012-08-01 19:39:39

+0

谢谢!这当然有诀窍。有几个问题:(1)向SentenceList添加“[:]”是做什么的? (2)关于如何使代码更高效的任何快速建议?我将把它应用于大型数据集。 (3)对于@mgilson,我该如何将它声明为一个集合? – 2012-08-01 19:42:12

+0

添加'[:]'列表的浅表副本。你可以创建一个像'wordList = set(['xxx','yyy'])''的集合。 – 2012-08-01 19:44:45

1

This answer与此类似。为了应用它,我们需要一个谓词(一个参数的函数,它只返回TrueFalse)确定条目是否应该保留。

既然我们有一个叫做wordList在一组目标词:

wordList = set(('xxx', 'yyy')) 

这个谓词应该工作:

def keep_sentence(sentence): 
    for wordTuple in sentence: 
     for entry in wordTuple: 
      if entry in wordList: 
       return False 
    return True # Only executed if we didn't return false earlier 

现在,我们有一个谓语,我们可以更换的sentenceList内容只有keep_sentence告诉我们应该保留的句子:

sentenceList[:] = [x for x in sentenceList if keep_sentence(x)] 

至于应用到大型数据集 - 可能不会有比这更快的算法(或其他答案之一),没有并行化你的代码。为什么?为了检查每个句子是否包含目标词之一,我们必须查看每个句子中的每个词。你可以用一些不变的因素来减少你在每个句子上花费的时间,但这不会有很大的帮助。

如果您对此感兴趣,您可能需要查看multiprocessing模块,尤其是process pools