339 lines
9.6 KiB
VimL
339 lines
9.6 KiB
VimL
|
"=============================================================================
|
|||
|
" $Id: list.vim 236 2010-06-01 00:43:34Z luc.hermitte $
|
|||
|
" File: autoload/lh/list.vim {{{1
|
|||
|
" Author: Luc Hermitte <EMAIL:hermitte {at} free {dot} fr>
|
|||
|
" <URL:http://code.google.com/p/lh-vim/>
|
|||
|
" Version: 2.2.1
|
|||
|
" Created: 17th Apr 2007
|
|||
|
" Last Update: $Date: 2010-05-31 20:43:34 -0400 (Mon, 31 May 2010) $ (17th Apr 2007)
|
|||
|
"------------------------------------------------------------------------
|
|||
|
" Description:
|
|||
|
" Defines functions related to |Lists|
|
|||
|
"
|
|||
|
"------------------------------------------------------------------------
|
|||
|
" Installation:
|
|||
|
" Drop it into {rtp}/autoload/lh/
|
|||
|
" Vim 7+ required.
|
|||
|
" History:
|
|||
|
" v2.2.1:
|
|||
|
" (*) use :unlet in :for loop to support heterogeneous lists
|
|||
|
" (*) binary search algorithms (upper_bound, lower_bound, equal_range)
|
|||
|
" v2.2.0:
|
|||
|
" (*) new functions: lh#list#accumulate, lh#list#transform,
|
|||
|
" lh#list#transform_if, lh#list#find_if, lh#list#copy_if,
|
|||
|
" lh#list#subset, lh#list#intersect
|
|||
|
" (*) the functions are compatible with lh#function functors
|
|||
|
" v2.1.1:
|
|||
|
" (*) unique_sort
|
|||
|
" v2.0.7:
|
|||
|
" (*) Bug fix: lh#list#Match()
|
|||
|
" v2.0.6:
|
|||
|
" (*) lh#list#Find_if() supports search predicate, and start index
|
|||
|
" (*) lh#list#Match() supports start index
|
|||
|
" v2.0.0:
|
|||
|
" TODO: <20>missing features<65>
|
|||
|
" }}}1
|
|||
|
"=============================================================================
|
|||
|
|
|||
|
|
|||
|
"=============================================================================
|
|||
|
let s:cpo_save=&cpo
|
|||
|
set cpo&vim
|
|||
|
|
|||
|
"------------------------------------------------------------------------
|
|||
|
" ## Functions {{{1
|
|||
|
" # Debug {{{2
|
|||
|
function! lh#list#verbose(level)
|
|||
|
let s:verbose = a:level
|
|||
|
endfunction
|
|||
|
|
|||
|
function! s:Verbose(expr)
|
|||
|
if exists('s:verbose') && s:verbose
|
|||
|
echomsg a:expr
|
|||
|
endif
|
|||
|
endfunction
|
|||
|
|
|||
|
function! lh#list#debug(expr)
|
|||
|
return eval(a:expr)
|
|||
|
endfunction
|
|||
|
|
|||
|
"------------------------------------------------------------------------
|
|||
|
" # Public {{{2
|
|||
|
" Function: lh#list#Transform(input, output, action) {{{3
|
|||
|
" deprecated version
|
|||
|
function! lh#list#Transform(input, output, action)
|
|||
|
let new = map(copy(a:input), a:action)
|
|||
|
let res = extend(a:output,new)
|
|||
|
return res
|
|||
|
|
|||
|
for element in a:input
|
|||
|
let action = substitute(a:action, 'v:val','element', 'g')
|
|||
|
let res = eval(action)
|
|||
|
call add(a:output, res)
|
|||
|
unlet element " for heterogeneous lists
|
|||
|
endfor
|
|||
|
return a:output
|
|||
|
endfunction
|
|||
|
|
|||
|
function! lh#list#transform(input, output, action)
|
|||
|
for element in a:input
|
|||
|
let res = lh#function#execute(a:action, element)
|
|||
|
call add(a:output, res)
|
|||
|
unlet element " for heterogeneous lists
|
|||
|
endfor
|
|||
|
return a:output
|
|||
|
endfunction
|
|||
|
|
|||
|
function! lh#list#transform_if(input, output, action, predicate)
|
|||
|
for element in a:input
|
|||
|
if lh#function#execute(a:predicate, element)
|
|||
|
let res = lh#function#execute(a:action, element)
|
|||
|
call add(a:output, res)
|
|||
|
endif
|
|||
|
unlet element " for heterogeneous lists
|
|||
|
endfor
|
|||
|
return a:output
|
|||
|
endfunction
|
|||
|
|
|||
|
function! lh#list#copy_if(input, output, predicate)
|
|||
|
for element in a:input
|
|||
|
if lh#function#execute(a:predicate, element)
|
|||
|
call add(a:output, element)
|
|||
|
endif
|
|||
|
unlet element " for heterogeneous lists
|
|||
|
endfor
|
|||
|
return a:output
|
|||
|
endfunction
|
|||
|
|
|||
|
function! lh#list#accumulate(input, transformation, accumulator)
|
|||
|
let transformed = lh#list#transform(a:input, [], a:transformation)
|
|||
|
let res = lh#function#execute(a:accumulator, transformed)
|
|||
|
return res
|
|||
|
endfunction
|
|||
|
|
|||
|
" Function: lh#list#match(list, to_be_matched [, idx]) {{{3
|
|||
|
function! lh#list#match(list, to_be_matched, ...)
|
|||
|
let idx = (a:0>0) ? a:1 : 0
|
|||
|
while idx < len(a:list)
|
|||
|
if match(a:list[idx], a:to_be_matched) != -1
|
|||
|
return idx
|
|||
|
endif
|
|||
|
let idx += 1
|
|||
|
endwhile
|
|||
|
return -1
|
|||
|
endfunction
|
|||
|
function! lh#list#Match(list, to_be_matched, ...)
|
|||
|
let idx = (a:0>0) ? a:1 : 0
|
|||
|
return lh#list#match(a:list, a:to_be_matched, idx)
|
|||
|
endfunction
|
|||
|
|
|||
|
" Function: lh#list#Find_if(list, predicate [, predicate-arguments] [, start-pos]) {{{3
|
|||
|
function! lh#list#Find_if(list, predicate, ...)
|
|||
|
" Parameters
|
|||
|
let idx = 0
|
|||
|
let args = []
|
|||
|
if a:0 == 2
|
|||
|
let idx = a:2
|
|||
|
let args = a:1
|
|||
|
elseif a:0 == 1
|
|||
|
if type(a:1) == type([])
|
|||
|
let args = a:1
|
|||
|
elseif type(a:1) == type(42)
|
|||
|
let idx = a:1
|
|||
|
else
|
|||
|
throw "lh#list#Find_if: unexpected argument type"
|
|||
|
endif
|
|||
|
elseif a:0 != 0
|
|||
|
throw "lh#list#Find_if: unexpected number of arguments: lh#list#Find_if(list, predicate [, predicate-arguments] [, start-pos])"
|
|||
|
endif
|
|||
|
|
|||
|
" The search loop
|
|||
|
while idx != len(a:list)
|
|||
|
let predicate = substitute(a:predicate, 'v:val', 'a:list['.idx.']', 'g')
|
|||
|
let predicate = substitute(predicate, 'v:\(\d\+\)_', 'args[\1-1]', 'g')
|
|||
|
let res = eval(predicate)
|
|||
|
if res | return idx | endif
|
|||
|
let idx += 1
|
|||
|
endwhile
|
|||
|
return -1
|
|||
|
endfunction
|
|||
|
|
|||
|
" Function: lh#list#find_if(list, predicate [, predicate-arguments] [, start-pos]) {{{3
|
|||
|
function! lh#list#find_if(list, predicate, ...)
|
|||
|
" Parameters
|
|||
|
let idx = 0
|
|||
|
let args = []
|
|||
|
if a:0 == 1
|
|||
|
let idx = a:1
|
|||
|
elseif a:0 != 0
|
|||
|
throw "lh#list#find_if: unexpected number of arguments: lh#list#find_if(list, predicate [, start-pos])"
|
|||
|
endif
|
|||
|
|
|||
|
" The search loop
|
|||
|
while idx != len(a:list)
|
|||
|
" let predicate = substitute(a:predicate, 'v:val', 'a:list['.idx.']', 'g')
|
|||
|
let res = lh#function#execute(a:predicate, a:list[idx])
|
|||
|
if res | return idx | endif
|
|||
|
let idx += 1
|
|||
|
endwhile
|
|||
|
return -1
|
|||
|
endfunction
|
|||
|
|
|||
|
" Function: lh#list#lower_bound(sorted_list, value [, first[, last]]) {{{3
|
|||
|
function! lh#list#lower_bound(list, val, ...)
|
|||
|
let first = 0
|
|||
|
let last = len(a:list)
|
|||
|
if a:0 >= 1 | let first = a:1
|
|||
|
elseif a:0 >= 2 | let last = a:2
|
|||
|
elseif a:0 > 2
|
|||
|
throw "lh#list#equal_range: unexpected number of arguments: lh#list#equal_range(sorted_list, value [, first[, last]])"
|
|||
|
endif
|
|||
|
|
|||
|
let len = last - first
|
|||
|
|
|||
|
while len > 0
|
|||
|
let half = len / 2
|
|||
|
let middle = first + half
|
|||
|
if a:list[middle] < a:val
|
|||
|
let first = middle + 1
|
|||
|
let len -= half + 1
|
|||
|
else
|
|||
|
let len = half
|
|||
|
endif
|
|||
|
endwhile
|
|||
|
return first
|
|||
|
endfunction
|
|||
|
|
|||
|
" Function: lh#list#upper_bound(sorted_list, value [, first[, last]]) {{{3
|
|||
|
function! lh#list#upper_bound(list, val, ...)
|
|||
|
let first = 0
|
|||
|
let last = len(a:list)
|
|||
|
if a:0 >= 1 | let first = a:1
|
|||
|
elseif a:0 >= 2 | let last = a:2
|
|||
|
elseif a:0 > 2
|
|||
|
throw "lh#list#equal_range: unexpected number of arguments: lh#list#equal_range(sorted_list, value [, first[, last]])"
|
|||
|
endif
|
|||
|
|
|||
|
let len = last - first
|
|||
|
|
|||
|
while len > 0
|
|||
|
let half = len / 2
|
|||
|
let middle = first + half
|
|||
|
if a:val < a:list[middle]
|
|||
|
let len = half
|
|||
|
else
|
|||
|
let first = middle + 1
|
|||
|
let len -= half + 1
|
|||
|
endif
|
|||
|
endwhile
|
|||
|
return first
|
|||
|
endfunction
|
|||
|
|
|||
|
" Function: lh#list#equal_range(sorted_list, value [, first[, last]]) {{{3
|
|||
|
" @return [f, l], where
|
|||
|
" f : First position where {value} could be inserted
|
|||
|
" l : Last position where {value} could be inserted
|
|||
|
function! lh#list#equal_range(list, val, ...)
|
|||
|
let first = 0
|
|||
|
let last = len(a:list)
|
|||
|
|
|||
|
" Parameters
|
|||
|
if a:0 >= 1 | let first = a:1
|
|||
|
elseif a:0 >= 2 | let last = a:2
|
|||
|
elseif a:0 > 2
|
|||
|
throw "lh#list#equal_range: unexpected number of arguments: lh#list#equal_range(sorted_list, value [, first[, last]])"
|
|||
|
endif
|
|||
|
|
|||
|
" The search loop ( == STLPort's equal_range)
|
|||
|
|
|||
|
let len = last - first
|
|||
|
while len > 0
|
|||
|
let half = len / 2
|
|||
|
let middle = first + half
|
|||
|
if a:list[middle] < a:val
|
|||
|
let first = middle + 1
|
|||
|
let len -= half + 1
|
|||
|
elseif a:val < a:list[middle]
|
|||
|
let len = half
|
|||
|
else
|
|||
|
let left = lh#list#lower_bound(a:list, a:val, first, middle)
|
|||
|
let right = lh#list#upper_bound(a:list, a:val, middle+1, first+len)
|
|||
|
return [left, right]
|
|||
|
endif
|
|||
|
|
|||
|
" let predicate = substitute(a:predicate, 'v:val', 'a:list['.idx.']', 'g')
|
|||
|
" let res = lh#function#execute(a:predicate, a:list[idx])
|
|||
|
endwhile
|
|||
|
return [first, first]
|
|||
|
endfunction
|
|||
|
|
|||
|
" Function: lh#list#unique_sort(list [, func]) {{{3
|
|||
|
" See also http://vim.wikia.com/wiki/Unique_sorting
|
|||
|
"
|
|||
|
" Works like sort(), optionally taking in a comparator (just like the
|
|||
|
" original), except that duplicate entries will be removed.
|
|||
|
" todo: support another argument that act as an equality predicate
|
|||
|
function! lh#list#unique_sort(list, ...)
|
|||
|
let dictionary = {}
|
|||
|
for i in a:list
|
|||
|
let dictionary[string(i)] = i
|
|||
|
endfor
|
|||
|
let result = []
|
|||
|
" echo join(values(dictionary),"\n")
|
|||
|
if ( exists( 'a:1' ) )
|
|||
|
let result = sort( values( dictionary ), a:1 )
|
|||
|
else
|
|||
|
let result = sort( values( dictionary ) )
|
|||
|
endif
|
|||
|
return result
|
|||
|
endfunction
|
|||
|
|
|||
|
function! lh#list#unique_sort2(list, ...)
|
|||
|
let list = copy(a:list)
|
|||
|
if ( exists( 'a:1' ) )
|
|||
|
call sort(list, a:1 )
|
|||
|
else
|
|||
|
call sort(list)
|
|||
|
endif
|
|||
|
if len(list) <= 1 | return list | endif
|
|||
|
let result = [ list[0] ]
|
|||
|
let last = list[0]
|
|||
|
let i = 1
|
|||
|
while i < len(list)
|
|||
|
if last != list[i]
|
|||
|
let last = list[i]
|
|||
|
call add(result, last)
|
|||
|
endif
|
|||
|
let i += 1
|
|||
|
endwhile
|
|||
|
return result
|
|||
|
endfunction
|
|||
|
|
|||
|
" Function: lh#list#subset(list, indices) {{{3
|
|||
|
function! lh#list#subset(list, indices)
|
|||
|
let result=[]
|
|||
|
for e in a:indices
|
|||
|
call add(result, a:list[e])
|
|||
|
endfor
|
|||
|
return result
|
|||
|
endfunction
|
|||
|
|
|||
|
" Function: lh#list#intersect(list1, list2) {{{3
|
|||
|
function! lh#list#intersect(list1, list2)
|
|||
|
let result = copy(a:list1)
|
|||
|
call filter(result, 'index(a:list2, v:val) >= 0')
|
|||
|
return result
|
|||
|
|
|||
|
for e in a:list1
|
|||
|
if index(a:list2, e) > 0
|
|||
|
call result(result, e)
|
|||
|
endif
|
|||
|
endfor
|
|||
|
endfunction
|
|||
|
|
|||
|
" Functions }}}1
|
|||
|
"------------------------------------------------------------------------
|
|||
|
let &cpo=s:cpo_save
|
|||
|
"=============================================================================
|
|||
|
" vim600: set fdm=marker:
|