2010-10-24 50 views
2

[編輯]如何從一個特定的點在重複序列(Python)的

從反饋/答案我已經收到,我收集有關於原來的問題有些混亂。因此,這個問題我已經減少到其最基本的形式

這裏有問題的相關事實:

  1. 我有一個排序序列:小號
  2. 我有一個項目(記)這是保證包含在小號
  3. 我想發現()算法返回一個迭代器(ITER)指向
  4. 獲得迭代器後,我希望能夠在在元素上向前遍歷(向後?)s ,起價(含)

對於我的同胞C++程序員誰也可以計劃在Python,世界衛生大會t我要求的是,相當於:

const_iterator std::find (const key_type& x) const; 

然後可以使用返回的迭代器迭代序列。我只是試圖找到(雙關意外),如果在Python中有類似的內置算法,以免我不得不重新發明輪子。

+3

您使用的是有序字典,對不對? (普通的Python字典是無序的!) – user470379 2010-10-24 01:52:35

+0

我認爲你最好給我們一個你想要做什麼的例子,以及字典是什麼(它將什麼映射到什麼?)以及你如何保證總是返回(? ?)從字典查找的關鍵字(什麼?),什麼是「關鍵字列表」,以及「拼接」是指「切片」還是別的。 – 2010-10-24 01:59:38

回答

1

鑑於您的相關事實:

>>> import bisect 
>>> def find_fwd_iter(S, i): 
...  j = bisect.bisect_left(S, i) 
...  for k in xrange(j, len(S)): 
...   yield S[k] 
... 
>>> def find_bkwd_iter(S, i): 
...  j = bisect.bisect_left(S, i) 
...  for k in xrange(j, -1, -1): 
...   yield S[k] 
... 
>>> L = [100, 150, 200, 300, 400] 
>>> list(find_fwd_iter(L, 200)) 
[200, 300, 400] 
>>> list(find_bkwd_iter(L, 200)) 
[200, 150, 100] 
>>> 
+0

不錯,簡單,簡短,甜蜜,尤其是對於像我這樣的新手而言。這就是我所說的詩歌 – skyeagle 2010-10-25 10:26:47

0

一個更簡單的方法(儘管較慢)將使用filter並在該日期之前/之後過濾鍵。過濾器必須處理列表中的每個元素,而不是切片不需要。

1

是的,你可以這樣做:

import itertools 
from datetime import datetime 

data = { 
     "2008-11-10 17:53:59":"data", 
     "2005-11-10 17:53:59":"data", 
} 

list_ = data.keys() 
new_list = [datetime.strptime(x, "%Y-%m-%d %H:%M:%S") for x in list_] 

begin_date = datetime.strptime("2007-11-10 17:53:59", "%Y-%m-%d %H:%M:%S") 

for i in itertools.ifilter(lambda x: x > begin_date, new_list): 
    print i 
+1

爲什麼不使用生成器表達式而不是爲'new_list'創建列表? – aaronasterling 2010-10-24 02:38:54

+0

@aaronasterling:是的,它可以很好地工作,並且在處理大型字典時也可以節省一些內存使用。 – mouad 2010-10-24 02:57:55

0

你可以做

def on_or_after(date): 
    from itertools import dropwhile 
    sorted_items = sorted(date_dictionary.iteritems()) 
    def before_date(pair): 
     return pair[0] < date 
    on_or_after_date = dropwhile(before_date, sorted_items) 

我認爲這是對有效率,因爲它會得到,如果你只是在做一個這樣的查詢在每個排序的集合上。 on_or_after_date將迭代(日期,值)對。

另一種選擇是建立一個字典作爲一個單獨的索引排序列表:

sorted_items = sorted(date_dictionary.iteritems()) 
date_index = dict((key, i) for i, key in enumerate(sorted_items.keys())) 

然後拿到項目或與

def on_or_after(date): 
    return sorted_items[date_index[date]:] 

這第二種方法會日期後如果你要對同一系列的排序日期進行大量查詢(這聽起來像是你),那麼速度會更快。

如果您想真正快速地對排序日期進行切片,可以通過將其存儲在元組而不是列表中來看到一些改進。雖然我可能是錯的。

note上述代碼未經測試,請告知我是否無效,並且您無法理清原因。

0

首先,這個問題與字典無關。您正在對排序的list進行操作。您正在使用結果,但這與問題無關。

你想要bisect模塊,它實現二進制搜索。從您的代碼開始:

import bisect 
mydict = { 
     "2001-01-01":"data1", 
     "2005-01-02":"data2", 
     "2002-01-01":"data3", 
     "2004-01-02":"data4", 
} 

# ['2001-01-01', '2002-01-01', '2004-01-02', '2005-01-02']: 
sorted_dates = sorted(mydict) 

# Iterates over 2002-01-01, 2004-01-02 and 2005-01-02: 
offset = bisect.bisect_left(sorted_dates, "2002-01-01") 
for item in sorted_dates[offset:]: 
    print item 
+1

(原始問題分散且混亂,說明不清楚,所以我不確定這是不是他真正要問的問題,我再讀了幾次,但我仍然不確定。)聳聳肩: – 2010-10-24 03:20:06

1

如果你知道一個事實,即在您的序列中的項目進行排序,你可以只用生成器表達式:

(item for item in seq if item >= 5) 

這將返回一個發電機;它實際上並沒有遍歷列表,直到你迭代它,即:

for item in (item for item in seq if item > 5) 
    print item 

只會遍歷seq一次。

使用生成器表達式像這樣幾乎是相同的使用itertools.ifilter,其產生的發生器,在迭代列表僅返回符合過濾條件的值:

>>> import itertools 
>>> seq = [1, 2, 3, 4, 5, 6, 7] 
>>> list(itertools.ifilter(lambda x: x>=3, seq)) 
[3, 4, 5, 6, 7] 

我不知道爲什麼(除了向後兼容性)我們現在需要itertools.ifilter現在我們有發生器表達式,但itertools中的其他方法是非常寶貴的。

例如,如果你不知道知道你的序列是排序的,而你仍然想從已知的項目開始返回序列中的所有內容,那麼你就不能使用生成器表達式。相反,請使用itertools.dropwhile。這將產生一個發電機迭代列表跳過值,直到它找到一個符合過濾條件:

>>> seq = [1, 2, 4, 3, 5, 6, 7] 
>>> list(itertools.dropwhile(lambda x: x != 3, seq)) 
[3, 5, 6, 7] 

至於搜索向後推移,如果你正在使用的序列實際上是一個序列,這隻會工作(如列表,即結束,可以向後導航),而不僅僅是任何可迭代的(例如返回下一個素數的生成器)。要做到這一點,使用reversed功能,例如:

(item for item in reversed(seq) if item >= 5) 
+0

這是我正在尋找的那種東西。不幸的是,我沒有使用Generators或lambda函數的經驗 - 所以我不瞭解你寫的東西(我對Python很陌生)。我不得不承認,我想要做的大部分事情似乎都涉及到發電機和/或lambda - 所以我想它是時候咬緊牙關了。我看過這個文檔:http://heather.cs.ucdavis.edu/~matloff/Python/PyIterGen.pdf這是一個好的開始/介紹還是你有更好的資源鏈接? – skyeagle 2010-10-25 00:19:35

+0

關於發電機,大衛比茲利救援:http://www.dabeaz.com/generators/。就lambda函數而言,lambda函數只是一個聲明爲內聯的函數。您可以輕鬆編寫一個名爲'item_in_range(x)'的函數並編寫'itertools.ifilter(item_in_range,seq)'。 – 2010-10-25 04:45:34

相關問題