2010-06-18 62 views
2

我有一個用來檢查某個值(例如,選項或功能參數)是否一些模型相匹配的腳本。我希望我的腳本能夠檢查遞歸數據結構。所以,問題是:有沒有更有效的方法然後再遍歷包含引用到已經選中的列表和字典的一些列表。示例代碼:檢查是否一些對象已經被測試

function s:AlreadyChecked(arg, checkedlst) 
    if type(a:arg)!=type([]) && type(a:arg)!=type({}) 
     return 0 
    endif 
    for obj in a:checkedlst 
     if a:arg is obj 
      return 1 
     endif 
    endfor 
    call add(a:checkedlst, a:arg) 
    return 0 
endfunction 

尋找一種方式來排序checkedlst(即比較引用,而不是由他們找到的值),甚至使用哈希值。

回答

1

正如我猜你已經發現,Vim不會允許列表或解釋變量作爲字典鍵。這意味着你不能,例如,可以填充一個「檢查」字典是這樣的:

" Unless k is a String, this won't work. 
:let checked[k] = 1 

它還缺少一個簡單的方法來生成一個列表或字典一個唯一的字符串,所以這要麼是不可靠:

:let checked[ string(k) ] = 1 

更好的方法是標記數據結構本身而不是嘗試構建散列表。如果你不介意暫時讓你的數據結構,只讀,這樣做的一個方法是使用:lockvar

:let someDict = {} 
:let someDict['foo'] = [1, 2, 3] 
:lockvar 1 someDict 

標誌着someDict爲只讀。 (該1限制了鎖定到詞典的頂層,因此嵌套結構不會自動鎖定。)的可變的鎖定狀態可以檢查這樣的:

:echo islocked('someDict') 
1 

:echo islocked("someDict['foo']") 
0 

:echo islocked("someDict['foo'][0]") 
0 

解鎖也很容易:

:unlockvar 1 someDict 

所以,現在我們有標記嵌套數據結構的各個層次的「檢查」,一種方法來查詢一個特定的水平是否被標記的技術和方法,以消除所有的痕跡時,我們就大功告成了。全部放在一起,AlreadyChecked()可以修改,像這樣:

function! s:AlreadyChecked(arg, checkedlst) 

    if type(a:arg)!=type([]) && type(a:arg)!=type({}) 
     return 0 
    endif 

    " If this particular List or Dictionary has already been checked, just 
    " return true immediately. 
    " 
    if islocked('a:arg') 
     echo "Already checked." 
     return 1 
    endif 

    " Lock the List or Dictionary to mark this item as already 
    " checked. Note that only the top level of the List or Dictionary 
    " is locked; values are not locked. 
    " 
    lockvar 1 a:arg 

    " Remember everything we've locked, so it can be unlocked once 
    " we're done. 
    " 
    call add(a:checkedlst, a:arg) 

    return 0 

endfunction 

一旦你做檢查,只是刪除所有的鎖:

for obj in a:checkedlst 
    unlockvar 1 obj 
endfor 

希望這有助於。這是對鎖定設施的濫用,但也許它會滿足您的需求。

+0

感謝,如果我結合了'deepcopy'(與其來源無關,將清除鎖,使數據)你的答案,那麼它應該工作的罰款。 – ZyX 2010-08-08 16:13:10

+0

但你有一個錯誤:'讓someDict {「富」} = ...'將創建一個變量'someDictfoo',你應該把它要麼改變爲'someDict.foo'或'someDict [「富」]',參見':h curly-braces-names'。 – ZyX 2010-08-08 16:17:19

+0

啊,很好。這是Perl和Vimscript之間切換太快的原因。 :-)我已經更正了這些示例以使用正確的語法。很高興答案仍然有用。 – 2010-08-09 17:20:48

相關問題