2015-04-07 8 views
2

У меня есть список, который идет как это:Создание меньшего списка из существующего списка

>>> list1 = ['Mary','had','a','little','lamb','which','was','very','naughty'] 

У меня было требование, чтобы создать еще один список (list2) из list1, который создается итерация list1 и нахождения элемент маленький, а затем добавление немного и каждый элемент, который следует за , немного до list2.

Немного прочитал и нашел, что оттуда от itertools было сделано только для моего требования.

>>> from itertools import dropwhile 
>>> list2 = list(dropwhile(lambda l: 'little' not in l, list1)) 
>>> list2 
['little', 'lamb', 'which', 'was', 'very', 'naughty'] 

Работает именно так, как я хочу.

Однако, теперь у меня есть требование, чтобы указать конечный элемент как well.So я хочу список элементов из немного к очень оба включительно следующим образом:

>>>list3 
['little', 'lamb', 'which', 'was', 'very'] 

Как сделать что с подобным подходом?

+0

Вы должны серьезно определить условия пограничной линии, потому что вы получаете ответы, которые могут взорваться несколько раз. Всегда ли гарантировано присутствие элементов? Они происходят только один раз каждый? Что произойдет, если нет. Гарантирован ли заказ? Что должно произойти, если 'very' до« непослушного »... – luk32

+0

@ luk32 ... я понимаю ваши проблемы, но я позаботился об этих условиях пограничной линии. Мое намерение состояло в том, чтобы получить логику, когда все эти граничные условия позаботились .. – Amistad

ответ

1

Если вы хотите продолжить работу с itertools (не заботясь о производительности):

from itertools import dropwhile 
list1 = ['Mary','had','a','little','lamb','which','was','very','naughty'] 

list2 = list(dropwhile(lambda x: x!="little", list1)) 
list3 = list(dropwhile(lambda x: x!="very", reversed(list2))) 
print list(reversed(list3)) 

мощность:

['little', 'lamb', 'which', 'was', 'very'] 

Если вы заботитесь о производительности, вы должны определить пользовательскую логику (благодаря @Kasra):

list1 = ['Mary','had','a','little','lamb','which','was','very','naughty'] 

def drop(sequence,start,end): 
    keep = False 
    for item in sequence: 
     if item == start: 
      keep = True 
     if keep and item == end: 
      yield item 
      break 
     if keep: 
      yield item 

list3 = drop(list1, 'little', 'very') 

print list(list3) 
+0

только для того, чтобы понять .. Какая проблема с производительностью здесь ..? это накладные расходы на вспять список и снова отменить его обратно? – Amistad

+0

Да, каждый 'list' и' reverse' выполняют полное сканирование списка – Don

1

Простой способ сделать это без использования itertools может выглядеть некоторые вещи, как:

start = list1.index("little") 
end = list1.index("very") 
list3 = list1[start:end+1] 

или просто вы можете написать:

list3 = list1[list1.index("little"):list1.index("very")+1] 
+1

Это не удается, когда 'very' появляется перед' little'. – rightfold

+1

Чтобы обработать этот проход 'start' в качестве второго аргумента' end = list1.index ("very") '. –

0

Вы можете сделать список нарезку.

>>> list1 = ['Mary','had','a','little','lamb','which','was','very','naughty'] 
>>> list1[list1.index('little'):list1.index('very')+1] 
['little', 'lamb', 'which', 'was', 'very'] 
1

Это должен сделать трюк:

list1[list1.index('little'):-list1[::-1].index('very')] 

Результата:

['little', 'lamb', 'which', 'was', 'very'] 

Ищет второе ключевое слово в обратном списке, а затем использовать отрицательный индекс в исходном списке.

3

Вы можете использовать пользовательскую функцию, чтобы вернуть генератор:

def drop(iterable,start,end): 

    for i,x in enumerate(iterable): 
     if x==start : 
      for y in iterable[i:]: 
       if y!=end: 
        yield y 
       else: 
        yield end 
        break 

Демо:

list1 = ['Mary','had','a','little','lamb','which','was','very','naughty'] 
print list(drop(list1,'little','very')) 
['little', 'lamb', 'which', 'was', 'very'] 

Примечание, что это решение быстрее, чем при использовании list.index, как ее порядок О (п), и вы используете его 2 раза, но для предыдущей функции вы повторяете весь свой список 1 раз, кроме того, один индекс в iterable[i:], что его порядок меньше O (n), поэтому он быстрее.

Для лучшего понимания посмотрите на следующие бенчмаркинга:

from timeit import timeit 

s1=""" 
list1 = ['Mary','had','a','little','lamb','which','was','very','naughty'] 
list1[list1.index("little"):list1.index("very")+1] 
""" 
s2=""" 
def drop(iterable,start,end): 

    for i,x in enumerate(iterable): 
     if x==start : 
      for y in iterable[i:]: 
       if y!=end: 
        yield y 
       else: 
        yield end 
        break 
list1 = ['Mary','had','a','little','lamb','which','was','very','naughty'] 
drop(list1,'little','very') 
    """ 


print ' first: ' ,timeit(stmt=s1, number=1000000) 
print 'second : ',timeit(stmt=s2, number=1000000) 

результат:

first: 5.87736296654 
second : 5.01044201851 
+1

это действительно информативно .. спасибо – Amistad

+1

Плюс 1 ... Всегда отлично, когда вы изучаете производительность непифонных решений – JuniorCompressor

+0

, просто чтобы понять .. что означает порядок O (n)? – Amistad

1

Решение, которое не предполагает, что «мало» пред «очень»:

def list_range(ls, a, b): 
    a_i, b_i = ls.index(a), ls.index(b) 
    if a_i < b_i: 
     return ls[a_i:b_i+1] 
    else: 
     return ls[a_i:b_i-1:-1] 

list1 = ['Mary','had','a','little','lamb','which','was','very','naughty'] 
print list_range(list1, 'little', 'very') 
Смежные вопросы