123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
- "=============================================================================
- " $Id: list.vim 520 2012-03-19 18:09:15Z 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/>
- " License: GPLv3 with exceptions
- " <URL:http://code.google.com/p/lh-vim/wiki/License>
- " Version: 3.0.0
- " Created: 17th Apr 2007
- " Last Update: $Date: 2012-03-19 19:09:15 +0100 (Mon, 19 Mar 2012) $ (17th Apr 2007)
- "------------------------------------------------------------------------
- " Description:
- " Defines functions related to |Lists|
- "
- "------------------------------------------------------------------------
- " Installation:
- " Drop it into {rtp}/autoload/lh/
- " Vim 7+ required.
- " History:
- " v3.0.0:
- " (*) GPLv3
- " v2.2.2:
- " (*) new functions: lh#list#remove(), lh#list#matches(),
- " lh#list#not_found().
- " 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: «missing features»
- " }}}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#matches(list, to_be_matched [,idx]) {{{3
- " Return the list of indices that match {to_be_matched}
- function! lh#list#matches(list, to_be_matched, ...)
- let res = []
- let idx = (a:0>0) ? a:1 : 0
- while idx < len(a:list)
- if match(a:list[idx], a:to_be_matched) != -1
- let res += [idx]
- endif
- let idx += 1
- endwhile
- return res
- 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)
- " echomsg string(predicate) . " --> " . res
- 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#lower_bound: unexpected number of arguments: lh#list#lower_bound(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#upper_bound: unexpected number of arguments: lh#list#upper_bound(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#not_found(range) {{{3
- " @return whether the range returned from equal_range is empty (i.e. element not fount)
- function! lh#list#not_found(range)
- return a:range[0] == a:range[1]
- 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#remove(list, indices) {{{3
- function! lh#list#remove(list, indices)
- " assert(is_sorted(indices))
- let idx = reverse(copy(a:indices))
- for i in idx
- call remove(a:list, i)
- endfor
- return a:list
- 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:
|