*vital/Data/List.txt*		list utilities library.

Maintainer: ujihisa <ujihisa at gmail com>

==============================================================================
CONTENTS				*Vital.Data.List-contents*

INTRODUCTION			|Vital.Data.List-introduction|
INTERFACE			|Vital.Data.List-interface|
  Functions			  |Vital.Data.List-functions|

==============================================================================
INTRODUCTION				*Vital.Data.List-introduction*

*Vital.Data.List* is a list utilities library.  It provides some functions to
manipulate |List|.

>
	let s:V = vital#{plugin-name}#new()
	let s:L = s:V.import("Data.List")

	let s = []
	echo s:L.push(s, 1)
	" [1]
	echo s:L.push(s, 2)
	" [1, 2]
	echo s:L.push(s, 3)
	" [1, 2, 3]
	echo s
	" [1, 2, 3]
	echo s:L.pop(s)
	" 3
	echo s:L.pop(s)
	" 2
	echo s
	" [1]
<

==============================================================================
INTERFACE				*Vital.Data.List-interface*
------------------------------------------------------------------------------
FUNCTIONS				*Vital.Data.List-functions*

pop({list})				*Vital.Data.List.pop()*
	Removes the last element from |List| {list} and returns the element,
	as if the {list} is a stack.

push({list}, {val})			*Vital.Data.List.push()*
	Appends {val} to the end of |List| {list} and returns the list itself,
	as if the {list} is a stack.

shift({list})				*Vital.Data.List.shift()*
	Removes the first element from |List| {list} and returns the element.

unshift({list}, {val})			*Vital.Data.List.unshift()*
	Inserts {val} to the head of |List| {list} and returns the list
	itself.

cons({val}, {list})			*Vital.Data.List.cons()*
	Makes new |List| which first item is {val} and the rest of items are
	|List| {list}.
	See also: |Vital.Data.List.conj()|
>
	echo s:L.cons(1, [2, 3])
	" [1, 2, 3]
	echo s:L.cons(1, [])
	" [1]
	echo s:L.cons([1], [2, 3])
	" [[1], 2, 3]
	echo s:L.cons([1], 2)
	" ERROR: E745
<

conj({list}, {val})			*Vital.Data.List.conj()*
	Makes new |List| which first items are |List| {list} and the final
	item is {val}.
	See also: |Vital.Data.List.cons()|
>
	echo s:L.conj([2, 3], 1)
	" [2, 3, 1]
	echo s:L.conj([], 1)
	" [1]
	echo s:L.conj([2, 3], [1])
	" [2, 3, [1]]
	echo s:L.conj(2, [1])
	" ERROR: E745
<

uniq({list})			*Vital.Data.List.uniq()*
	Removes duplicate elements from |List| {list}, nondestructively.  In
	particular, it keeps only the first occurrence of each element.
	See also: |Vital.Data.List.uniq_by()|
>
	uniq(['vim', 'emacs', 'vim', 'vim']) == ['vim', 'emacs']
<

uniq_by({list}, {str})			*Vital.Data.List.uniq_by()*
	Removes duplicate elements from |List| {list}, nondestructively.  In
	particular, it keeps only the first occurrence of each element.  The
	uniqueness is judged with the value {str} to which a formula is
	applied.
	See also: |Vital.Data.List.uniq()|
>
	uniq_by(
	\ ['vim', 'Vim', 'VIM', 'emacs', 'Emacs', 'EMACS', 'gVim', 'GVIM'],
	\ 'tolower(v:val)') == ['vim', 'emacs', 'gVim']
<

clear({list})				*Vital.Data.List.clear()*
	Removes all the items of |List| {list}.  Returns the empty list.

concat({list})				*Vital.Data.List.concat()*
	Concatenates |List| {list} of lists.
>
	echo s:L.concat([[1], [2, 3]])
	" [1, 2, 3]
<
	This is similar to |Vital.Data.List.flatten()| but this doesn't
	flatten recursively.

flatten({list} [, {limit}])		*Vital.Data.List.flatten()*
	Take each {list} elements in |List| {list} into a new {list}
	recursively.  When the {limit} argument is given, the function keeps
	nested items by the {limit} is maximum size.
>
	echo s:L.flatten([[1], [2, 3]])
	" [1, 2, 3]
	echo s:L.flatten([[1], 2, 3])
	" [1, 2, 3]
	echo s:L.flatten([[['a']], [[['b']], 'c']], 2)
	" ['a', ['b'], 'c']
<
sort({list}, {expr})			*Vital.Data.List.sort()*
	Sorts the items in |List| {list} in-place.  Returns {list}.  {expr}
	must be a |String| or a |Funcref|.  When {expr} is a |Funcref|, this
	function returns the same result as |sort()|.  When {expr} is a
	|String|, this function uses {expr} to compare items.  Inside {expr}
	a:a and a:b have the value of the current items.  The evaluating
	result of {expr} must have zero if they are equal, 1 or bigger if a:a
	sorts after the a:b, -1 or smaller if a:a sorts before a:b.
>
	function! MyCompare(i1, i2)
	  return a:i1 ==
	    \ a:i2 ?        0 :
	    \ a:i1 > a:i2 ? 1 :
	    \               -1
	endfunction

	let list = ['pineapple', 'orange', 'banana', 'apple']
	echo s:L.sort(copy(list), function('MyCompare'))
	" ['apple', 'banana', 'orange', 'pineapple']

	echo s:L.sort([3, 1, 2], 'a:a - a:b')
	" [1, 2, 3]

	echo s:L.sort(copy(list), 'len(a:a)-len(a:b)')
	" ['apple', 'orange', 'banana', 'pineapple']
<
sort_by({list}, {expr})			*Vital.Data.List.sort_by()*
	Returns a sorted |List| with key in |List| {list}.

max_by({list}, {expr})			*Vital.Data.List.max_by()*
	Returns a maximum value in {list} through given {expr}.
	Returns 0 if {list} is empty.
	"v:val" can be used in {expr}.
>
	echo s:L.max_by(['pineapple','orange','banana','apple'], 'len(v:val)')
	" pineapple
	echo s:L.max_by([20, -50, -15, 30], 'abs(v:val)')
	" -50
<

min_by({list}, {expr})			*Vital.Data.List.min_by()*
	Returns a minimum value in |List| {list} through given {expr}.
	Returns 0 if {list} is empty.
	"v:val" can be used in {expr}.
>
	echo s:L.min_by(['pineapple','orange','banana','apple'], 'len(v:val)')
	" apple
	echo s:L.min_by([20, -50, -15, 30], 'abs(v:val)')
	" -15
<
char_range({from}, {to})		*Vital.Data.List.char_range()*
	Returns a |List| of letters from {from} to {to}.

has({list}, {value})			*Vital.Data.List.has()*
	Returns Number 1 if {value} is in |List| {list}, otherwise zero.

has_index({list}, {index})		*Vital.Data.List.has_index()*
	Returns Number 1 if can point to {index} for |List| {list}, otherwise
	zero.  If {index} is negative Number, this function returns zero.

span({expr}, {list})			*Vital.Data.List.span()*
	Returns a list of two lists where concatenation of them is
	equal to {list}, all the items of the first list satisfy {expr} and
	the first item of the second list does not satisfy {expr}.
	Inside {expr} |v:val| has the value of the current item.
>
	echo s:L.span("v:val==1", [1, 2])
	" [[1], [2]]
	echo s:L.span('v:val < 5', [1, 3, 5, 2])
	" [[1, 3], [5, 2]]
	echo s:L.span('v:val > 3', [1, 2, 3, 4, 5])
	" [[], [1, 2, 3, 4, 5]]
	echo s:L.span('v:val < 3', [1, 2, 3, 4, 5])
	" [[1, 2], [3, 4, 5]]
<
	If you know Haskell, this span() is like Haskell's Data.List.span just
	for your info.

break({expr}, {list})			*Vital.Data.List.break()*
	Returns a list of two lists where concatenation of them is
	equal to {list}, all the items of the first list do not satisfy
	{expr} and the first item of the second list satisfies {expr}.
	Inside {expr} |v:val| has the value of the current item.
>
	echo s:L.break("v:val==1", [1, 2])
	" [[], [1, 2]]
	echo s:L.break('v:val == 5', [1, 3, 5, 2])
	" [[1, 3], [5, 2]]
	echo s:L.break('v:val > 3', [1, 2, 3, 4, 5])
	" [[1, 2, 3], [4, 5]]
	echo s:L.break('v:val < 3', [1, 2, 3, 4, 5])
	" [[], [1, 2, 3, 4, 5]]
<
	If you know Haskell, this break() is like Haskell's Data.List.break
	just for your info.

take_while({expr}, {list})		*Vital.Data.List.take_while()*
	Returns a list which is from the beginning of the given {list} to an
	element that all of them satisfies given expression {expr}.
	Inside {expr} |v:val| has the value of the current item.
>
	echo s:L.take_while("v:val==1", [1, 2])
	" [1]
	echo s:L.take_while('v:val < 5', [1, 3, 5, 2])
	" [1, 3]
	echo s:L.take_while('v:val > 3', [1, 2, 3, 4, 5])
	" []
	echo s:L.take_while('v:val < 3', [1, 2, 3, 4, 5])
	" [1, 2]
<
	If you know Haskell, this take_while() is like Haskell's
	Data.List.takeWhile just for your info.

drop_while({expr}, {list})		*Vital.Data.List.drop_while()*
	Returns the suffix remaining after |Vital.Data.List.take_while()|.
	Inside {expr} |v:val| has the value of the current item.
>
	echo s:L.drop_while("v:val==1", [1, 2])
	" [2]
	echo s:L.drop_while('v:val < 5', [1, 3, 5, 2])
	" [5, 2]
	echo s:L.drop_while('v:val > 3', [1, 2, 3, 4, 5])
	" [1, 2, 3, 4, 5]
	echo s:L.drop_while('v:val < 3', [1, 2, 3, 4, 5])
	" [3, 4, 5]
<
	If you know Haskell, this drop_while() is like Haskell's
	Data.List.dropWhile just for your info.

all({expr}, {list})			*Vital.Data.List.all()*
	Returns Number 1 if all the items in |List| {list} fulfill the
	condition {expr}, zero otherwise.
	If {list} is empty, this function returns 1.
>
	echo s:L.all('v:val % 2 == 0', [2, 8, 4, 6])
	" 1
	echo s:L.all('v:val % 2 == 1', [2, 8, 4, 6])
	" 0
	echo s:L.all('v:val % 2 == 0', [2, 8, 5, 6])
	" 0
	echo s:L.all('0 < v:val', [2, 8, 4, 6])
	" 1
	echo s:L.all('0 < v:val', [2, 0, 4, 6])
	" 0
<
	If you know Haskell, this all() is like Haskell's Prelude.all just for
	your info.

any({expr}, {list})			*Vital.Data.List.any()*
	Returns Number 1 if at least one item in |List| {list} fulfills the
	condition {expr}, zero otherwise.  If {list} is empty, this function
	returns 0.
>
	echo s:L.any('v:val % 2 == 0', [2, 8, 4, 6])
	" 1
	echo s:L.any('v:val % 2 == 1', [2, 8, 4, 6])
	" 0
	echo s:L.any('v:val % 2 == 0', [2, 8, 5, 6])
	" 1
	echo s:L.any('0 < v:val', [2, 8, 4, 6])
	" 1
	echo s:L.any('0 < v:val', [2, 0, 4, 6])
	" 1
<
	If you know Haskell, this any() is like Haskell's Prelude.any just for
	your info.

and({list})				*Vital.Data.List.and()*
	Returns Number 1 if all the items of |List| {list} are non-zero
	Numbers, zero otherwise.  If {list} is empty, this function returns 1.
>
	echo s:L.and([1, 2, 3, 1])
	" 1
	echo s:L.and([1, 0, 3, 1])
	" 0
	echo s:L.and([0, 0, 0, 0])
	" 0
<
	If you know Haskell, this and() is like Haskell's Prelude.and just for
	your info.

or({list})				*Vital.Data.List.or()*
	Returns Number 1 if at least one item in List {list} is non-zero,
	zero otherwise.  If {list} is empty, this function returns 0.
>
	echo s:L.or([1, 2, 3, 1])
	" 1
	echo s:L.or([1, 0, 3, 1])
	" 1
	echo s:L.or([0, 0, 0, 0])
	" 0
<
	If you know Haskell, this or() is like Haskell's Prelude.or just for
	your info.

partition({expr}, {list})		*Vital.Data.List.partition()*
	TODO
	Behaves like Haskell's Data.List.partition().

map_accum({expr}, {xs}, {init})		*Vital.Data.List.map_accum()*
	This is similar to |map()| but the followings are different:
	* it doesn't destroy {xs}
	* it holds previous accumulator
	* you also have to specify initial accumulator value
	* you also have to let {expr} return the next accumulator value
>
	List.map_accum('[v:val + v:memo, v:memo]', [1, 2, 3], 10)
	"=> [11, 12, 13]

	List.map_accum('[v:val + v:memo, v:memo + 1]', [1, 2, 3], 10)
	"=> [11, 13, 15]
<

foldl({f}, {init}, {xs})		*Vital.Data.List.foldl()*
	Reduces the list {xs} using the binary operator {f}, from left to
	right. The starting value of the reduction (typically the
	left-identity of the operator) is {init}.

	foldl(f, z, [x1, x2, ..., xn]) ==
	  f(... f(f(z, x1), x2) ..., xn)

	Examples:
>
	echo s:L.foldl('v:memo + v:val', 0, range(1, 10))
	" 55 := 1+2+3+4+5+6+7+8+9+10

	echo s:L.foldl('v:memo + v:val', 20, range(1, 10))
	" 75 := 20 + 1+2+3+4+5+6+7+8+9+10

	echo s:L.foldl('[v:memo, v:val]', [], [1, 2])
	" [[[], 1], 2]
<
	See also: foldl1, foldr, foldr1
	If you know Haskell, this foldl() is like Haskell's Data.List.foldl
	just for your info.

foldl1({f}, {xs})			*Vital.Data.List.foldl1()*
	TODO
	Behaves like Haskell's Data.List.foldl1().
>
	echo s:L.foldl1('v:memo + v:val', range(1, 10))
	" 55
	echo s:L.foldl1('[v:memo, v:val]', [1, 2])
	" [1, 2]
<
foldr({f}, {init}, {xs})		*Vital.Data.List.foldr()*
	TODO
	Behaves like Haskell's Data.List.foldr().
>
	echo s:L.foldr('v:memo + v:val', 0, range(1, 10))
	" 55
	echo s:L.foldr('v:memo + v:val', 20, range(1, 10))
	" 75
	echo s:L.foldr('[v:memo, v:val]', [], [1, 2])
	" [[[], 2], 1]
<
foldr1({f}, {xs})			*Vital.Data.List.foldr1()*
	TODO
	Behaves like Haskell's Data.List.foldr1().
>
	echo s:L.foldr1('v:memo + v:val', range(1, 10))
	" 55
	echo s:L.foldr1('[v:memo, v:val]', [1, 2])
	" [1, 2]
<
zip(...)				*Vital.Data.List.zip()*
	TODO
	Behaves like python's zip().
>
	echo s:L.zip([1, 2, 3], [4, 5, 6])
	" [[1, 4], [2, 5], [3, 6]]
	echo s:L.zip([1, 2, 3], [4, 5, 6], [7, 8, 9])
	" [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
<
with_index({list} [, {offset}])		*Vital.Data.List.with_index()*
	Returns {list} with index. {offset} means the base of index.
	If you specify {offset}, index starts with {offset}.
>
	echo s:L.with_index(['a', 'b', 'c'])
	" [['a', 0], ['b', 1], ['c', 2]]
	echo s:L.with_index(['a', 'b', 'c'], 2)
	" [['a', 2], ['b', 3], ['c', 4]]
<
	This function is useful when used with |:for|.
	For example, when you have lines as a list of string and you want to
	output a line with a line number to each line, you may write as below.
>
	for idx in range(1, len(lines))
		echo idx.': '.lines[idx]
	endfor
<
	This procedure can be rewritten using with_index() as below.
>
	for [line, idx] in s:L.with_index(lines, 1)
		echo idx.': '.line
	endfor
<
find({list}, {default}, {expr})			 *Vital.Data.List.find()*
	Returns the first value in {list} where the given {expr} is satisfied.
	{default} is returned when no item satisfies {expr}. {expr} must be a
	|String| or a |Funcref|.
>
	function! MyPredicate(x)
	  return a:x % 2 == 0
	endfunction

	echo s:L.find([1, 2, 3, 1, 2, 3], '*not-found*', function('MyPredicate'))
	" 2
	echo s:L.find([1, 2, 3, 1, 2, 3], '*not-found*', 'v:val % 2 == 0')
	" 2
	echo s:L.find([1, 2, 3], '*not-found*', 'v:val % 10 == 0')
	" '*not-found*'
<
	If you know Haskell, this find() is like Haskell's Data.List.find
	just for your info.

					*Vital.Data.List.find_index()*
find_index({list}, {expr} [, {start} [, {default}]])
	Returns the lowest index in {list} where the given {expr} is
	satisfied.
	If you specify {start}, start looking at the item with index {start}
	(may be negative for an item relative to the end).
	{default} is returned when no item satisfies {expr}. If {default} is
	omitted, -1 is used.
>
	echo s:L.find_index([0, 1, 2, 3], 'v:val%2 == 1')
	" 1
	echo s:L.find_index([0, 1, 2, 3], 'v:val > 10')
	" -1
<
					*Vital.Data.List.find_last_index()*
find_last_index({list}, {expr} [, {start} [, {default}]])
	Similar to find_index but this returns the highest index.
	Traversing is done in reverse order.
>
	echo s:L.find_last_index([0, 1, 2, 3], 'v:val%2 == 1')
	" 3
<
					*Vital.Data.List.find_indices()*
find_indices({list}, {expr} [, {start}])
	Similar to find_index but this returns all of indices specifying
	{expr}.
	When no indices found, empty list is returned.
>
	echo s:L.find_indices([0, 1, 2, 3], 'v:val%2 == 1')
	" [1, 3]
	echo s:L.find_indices([0, 1, 2, 3], 'v:val > 10')
	" []
<
has_common_items({list1}, {list2})	*Vital.Data.List.has_common_items()*
	Returns non-zero if a:list1 and a:list2 have a common item, otherwise
	zero.
>
	echo s:L.has_common_items(['a', 'b', 'c'], ['b', 'c'])
	" 1
	echo s:L.has_common_items(['a', 'c'], ['b', 'c'])
	" 1
	echo s:L.has_common_items(['a'], ['b', 'c'])
	" 0

intersect({list1}, {list2})		*Vital.Data.List.intersect()*
	Returns a |List| of common items between {list1} and {list2}, and it's
	unordered and uniquified.
>
	echo s:L.intersect(['a', 'b', 'c'], ['b', 'c'])
	" ['b', 'c']
	echo s:L.intersect(['a', 'c'], ['b', 'c'])
	" ['c']
	echo s:L.intersect(['a', 'a'], ['a', 'a'])
	" ['a']
	echo s:L.intersect(['a'], ['b', 'c'])
	" []
<
group_by({list}, {expr})		*Vital.Data.List.group_by()*
	Returns a |Dictionary| grouped by the result of {expr}.
	"v:val" can be used in {expr}.
>
	echo s:L.group_by(['a', 'b', 'ab'], 'len(v:val)')
	" {'1': ['a', 'b'], '2': ['ab']}
	echo s:L.group_by(['a', 'b', 'ab'], 'v:val[0]')
	" {'a': ['a', 'ab'], 'b': ['b']}
<
			      		*Vital.Data.List.binary_search()*
binary_search({list}, {expr}, [{func}, [{dict}]])
	Returns the index in {list} where the item has a value equal to
	{expr} by binary search.  {list} must be sorted.  If {expr} is not
	found, it returns -1.
	When {func} is given, it is used to check the lhs of {func} is less
	than the rhs of {func}.  {func} is the same as |sort()| of {func}.
	You can reuse {func} used for |sort()| to search with
	|Vital.Data.List.binary_search|.
	{dict} is used as "self" in "dict" function.
>
	echo s:L.binary_search([1, 3, 5, 7], 3)
	" 1
	echo s:L.binary_search([1, 3, 5, 7], 2)
	" -1

	function! CompareWithFirstElem(a, b)
		return a:a[0] < a:b[0] ? -1 : a:a[0] > a:b[0] ? 1 : 0
	endfunction
	echo s:L.binary_search([[1, 'd'], [3, 'c'], [5, 'b'], [7, 'a']], [3, 'c'], 'CompareWithFirstElem')
	" 1
	echo s:L.binary_search([[1, 'd'], [3, 'c'], [5, 'b'], [7, 'a']], [10, 'c'], 'CompareWithFirstElem')
	" -1
<
	You can control the condition for the search by {func}.  Below example
	shows the way to search a list by its length.
>
	let CompareByLength = {}
	function! CompareByLength.func(a, b) dict
		return len(a:a) - len(a:b)
	endfunction
	echo s:L.binary_search(['a', 'aa', 'aaa'], 'vi', CompareByLength.func, CompareByLength)
	" 1
	echo s:L.binary_search(['a', 'aa', 'aaa'], 'vivi', CompareByLength.func, CompareByLength)
	" -1
<
product({lists})			*Vital.Data.List.product()*
	Returns Cartesian product of elements in the {lists}.
>
	echo s:L.product([[1, 2], [4, 5]])
	" [[1, 4], [1, 5], [2, 4], [2, 5]]
	echo s:L.product([range(2), range(2), range(2)])
	" [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
<
permutations({list} [, {r}])	      	*Vital.Data.List.permutations()*
	Returns successive {r} length permutations of elements in the {list}.
	If {r} is not specified, then {r} defaults to the length of the {list}
	and all possible full-length permutations are generated.
>
	echo s:L.permutations([1, 2, 3])
	" [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
	echo s:L.permutations([1, 2, 3], 2)
	" [[1, 2] , [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
<
combinations({list}, {r})	      	*Vital.Data.List.combinations()*
	Returns successive {r} length combinations of elements in the {list}.
>
	echo s:L.combinations([1, 2, 3, 4], 2)
	" [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
	echo s:L.combinations([5, 2, 3, 1], 3)
	" [[5, 2, 3], [5, 2, 1], [5, 3, 1], [2, 3, 1]]
<

==============================================================================
vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl
