Vim documentation: vital/Data/List

main help file
vital/Data/List.txt           list utilities library.

Maintainer: ujihisa <ujihisa at gmail com>

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

INTRODUCTION                    Vital.Data.List-introduction
TERM                            Vital.Data.List.term
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")

        echo s:L.cons(1, [2, 3])
        " [1, 2, 3]

        echo s:L.conj([2, 3], 1)
        " [2, 3, 1]

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

        echo s:L.count({ x -> x % 2 == 0 }, [1, 2, 3, 4, 5])
        "=> 2

        echo s:L.intersect(['a', 'b', 'c'], ['b', 'c'])
        " ['b', 'c']

        s:L.new(3, { i -> i * 2 })
        "=> [0, 2, 4]

        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]]


==============================================================================
TERM                                    Vital.Data.List-term

{function}                              Vital.Data.List-term-function
        It's just Funcref, but also String as expression works fine for
        backward compatibility. String for this is DEPRECATED.

        For new code please always simply use Vim's expr-lambda notation for
        this.

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

new({size}, {f})                        Vital.Data.List.new()
        Creates a new List with given arguments. The given Funcref {f} is
        called for {size} times with index.

        Note that's vital Data.List does not provide a new wrapper list
        dictionary or whatever. It simply uses Vim's Lists.

        s:L.new(3, { i -> i * 2 })
        "=> [0, 2, 4]

        s:L.new(4, { -> 'hello' })
        "=> ['hello', 'hello', 'hello', 'hello']

        Basically this function is equivalent to the following one line.

        new(size, f) == map(range(a:size), a:f)



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

        Destructive. This modifies {list}.


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.

        Destructive. This modifies {list}.


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

        Destructive. This modifies {list}.


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

        Destructive. This modifies {list}.


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


        Non-destructive. This does not modify {list}.

uncons({list})                  Vital.Data.List.uncons()
        Returns a pair of a head element and tail elements.
        {list} must be nonempty, otherwise it throws an error.

        echo s:L.uncons([1, 2, 3, 4, 5])
        " [1, [2, 3, 4, 5]]
        echo s:L.uncons([1])
        " [1, []]
        echo s:L.uncons([])
        " ERROR: vital: Data.List: ...


        Non-destructive. This does not modify {list}.

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


        Non-destructive. This does not modify {list}.

map({list}, {function})                 Vital.Data.List.map()
        Use this if you'd like to keep the original list. Vim's built-in
        map() destroys the given {list}, but this doesn't.

        Generalized map(). The followings are different of map():
        * Don't require taking the index as the argument
           (See the section of 'If {expr2} is a Funcref...' in map())
        * Don't require copying
           (See the section of 'The operation is done in-place' in map())
        * Remove v:key support
        * Don't modify {list} itself.

        function! Succ(x) abort
          return a:x + 1
        endfunction

        echo s:L.map(range(0, 4), { x + 1 })
        " [1, 2, 3, 4, 5]
        echo s:L.map(range(0, 4), function('Succ'))
        " [1, 2, 3, 4, 5]
        echo s:L.map(range(0, 4), 'v:val + 1') " DEPRECATED
        " [1, 2, 3, 4, 5]

        But this maybe slower than builtin map().

        Non-destructive. This does not modify {list}.


filter({list}, {function})              Vital.Data.List.filter()
        Use this if you'd like to keep the original list. Vim's built-in
        filter() destroys the given {list}, but this doesn't.

        Generalized filter(). The followings are different of filter():
        * Don't require taking the index as the argument
           (See the section of 'If {expr2} is a Funcref...' in filter())
        * Don't require copying
           (See the section of 'The operation is done in-place' in filter())
        * Remove v:key support
        * Don't modify {list} itself.

        function! Even(x) abort
          return a:x % 2 is 0
        endfunction

        let xs = range(0, 9)
        echo s:L.filter(xs, function('Even'))
        " [0, 2, 4, 6, 8]
        echo s:L.filter(xs, 'v:val % 2 is 0')
        " [0, 2, 4, 6, 8]

        But this maybe slower than builtin filter().

        Non-destructive. This does not modify {list}.


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']


        Non-destructive. This does not modify {list}.

uniq_by({list}, {function})                     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 {function} 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']


        Non-destructive. This does not modify {list}.

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

        Destructive. This modifies {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.

        Non-destructive. This does not modify {list}.


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']


        Non-destructive. This does not modify {list}.

sort({list}, {function})                        Vital.Data.List.sort()
        Sorts the items in List {list} in-place.  Returns {list}. When
        {function} is a Funcref, this function returns the same result as
        sort(). When {function} is a String expression, this function uses
        {function} to compare items.  Inside {function} a:a and a:b have the
        value of the current items.  The evaluating result of {function} 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']

        Notice:
        If you use {function} as String expression, this function gives up
        job safety (thread safety). It may not work correctly. Please use
        lambda expression or partial applying of function if it can be used.

        Destructive. This modifies {list}.

sort_by({list}, {function})                     Vital.Data.List.sort_by()
        Returns a sorted List with key in List {list}.

        function! Lookup(x)
          return a:x.field
        endfunction

        let list = [{'field': 'pineapple'}, {'field': 'orange'}, {'field': 'banana'}, {'field': 'apple'}]

        echo s:L.sort_by(copy(list), 'v:val.field')
        " [{'field': 'apple'}, {'field': 'banana'}, {'field': 'orange'}, {'field': 'pineapple'}]

        echo s:L.sort_by(copy(list), function('Lookup'))
        " [{'field': 'apple'}, {'field': 'banana'}, {'field': 'orange'}, {'field': 'pineapple'}]


        Non-destructive. This does not modify {list}.


max_by({list}, {function})                      Vital.Data.List.max_by()
        Returns a maximum value in {list} through given {function}.
        Returns 0 if {list} is empty.
        "v:val" can be used in {function} if {function} is string expression.

        echo s:L.max_by(
        \ ['pineapple', 'orange', 'banana', 'apple'],
        \ 'len(v:val)')
        " pineapple
        echo s:L.max_by([20, -50, -15, 30], function('abs'))
        " -50


        Non-destructive. This does not modify {list}.

min_by({list}, {function})                      Vital.Data.List.min_by()
        Returns a minimum value in List {list} through given {function}.
        Returns 0 if {list} is empty.
        "v:val" can be used in {function} if {function} is string expression.

        echo s:L.min_by(
        \ ['pineapple', 'orange', 'banana', 'apple'],
        \ 'len(v:val)')
        " apple
        echo s:L.min_by([20, -50, -15, 30], function('abs'))
        " -15


        Non-destructive. This does not modify {list}.

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.

        Non-destructive. This does not modify {list}.


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.

        Non-destructive. This does not modify {list}.


span({function}, {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 {function} and
        the first item of the second list does not satisfy {function}.
        If {function} is the string expression, v:val has the value of the
        current item.

        function! Under5(x) abort
          return a:x < 5
        endfunction

        echo s:L.span('v:val < 5', [1, 3, 5, 2])
        " [[1, 3], [5, 2]]
        echo s:L.span(function('Under5'), [1, 3, 5, 2])
        " [[1, 3], [5, 2]]

        echo s:L.span('v:val==1', [1, 2])
        " [[1], [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.

        Non-destructive. This does not modify {list}.


break({function}, {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
        {function} and the first item of the second list satisfies {function}.
        If {function} is the string expression, v:val has the value of the
        current item.

        function! Is5(x) abort
          return a:x < 5
        endfunction

        echo s:L.break('v:val == 5', [1, 3, 5, 2])
        " [[1, 3], [5, 2]]
        echo s:L.break(function('Is5'), [1, 3, 5, 2])
        " [[1, 3], [5, 2]]

        echo s:L.break("v:val==1", [1, 2])
        " [[], [1, 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.

        Non-destructive. This does not modify {list}.


take_while({function}, {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 {function}.
        If {function} is the string expression, v:val has the value of the
        current item.

        function! Under5(x) abort
          return a:x < 5
        endfunction

        echo s:L.take_while('v:val < 5', [1, 3, 5, 2])
        " [1, 3]
        echo s:L.take_while(function('Under5'), [1, 3, 5, 2])
        " [1, 3]

        echo s:L.take_while('v:val == 1', [1, 2])
        " [1]
        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.

        Non-destructive. This does not modify {list}.


drop_while({function}, {list})          Vital.Data.List.drop_while()
        Returns the suffix remaining after Vital.Data.List.take_while().
        If {function} is the string expression, v:val has the value of the
        current item.

        function! Under5(x) abort
          return a:x < 5
        endfunction

        echo s:L.drop_while('v:val < 5', [1, 3, 5, 2])
        " [5, 2]
        echo s:L.drop_while(function('Under5'), [1, 3, 5, 2])
        " [5, 2]

        echo s:L.drop_while("v:val==1", [1, 2])
        " [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.

        Non-destructive. This does not modify {list}.


all({function}, {list})                 Vital.Data.List.all()
        Returns Number 1 if all the items in List {list} fulfill the
        condition {function}, zero otherwise.
        If {list} is empty, this function returns 1.

        function! Even(x) abort
          return a:x % 2 == 0
        endfunction

        echo s:L.all('v:val % 2 == 0', [2, 8, 4, 6])
        " 1
        echo s:L.all(function('Even'), [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.

        Non-destructive. This does not modify {list}.


any({function}, {list})                 Vital.Data.List.any()
        Returns Number 1 if at least one item in List {list} fulfills the
        condition {function}, zero otherwise.  If {list} is empty, this
        function returns 0.

        function! Even(x) abort
          return a:x % 2 == 0
        endfunction

        echo s:L.any('v:val % 2 == 0', [2, 8, 4, 6])
        " 1
        echo s:L.any(function('Even'), [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.

        Non-destructive. This does not modify {list}.


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.

        Non-destructive. This does not modify {list}.


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.

        Non-destructive. This does not modify {list}.


partition({function}, {list})           Vital.Data.List.partition()
        Gives a {function} as predicate. Takes a tuple. The tuple's first
        field is elements that satisfies the predicate. The second field is
        elements that doesn't satisfy the predicate.
        Behaves like Haskell's Data.List.partition().

        function! Even(x) abort
          return a:x % 2 == 0
        endfunction

        s:L.partition(function('Even'), range(5))
        " [[0, 2, 4], [1, 3]]
        s:L.partition('v:val % 2 == 0', range(5))
        " [[0, 2, 4], [1, 3]]


        Non-destructive. This does not modify {list}.

map_accum({function}, {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 {function} return the next accumulator value

        function! Plus(x, y) abort
          return [a:x + a:y, a:y]
        endfunction

        echo s:L.map_accum('[v:val + v:memo, v:memo]', [1, 2, 3], 10)
        " [11, 12, 13]
        echo s:L.map_accum(function('Plus'), [1, 2, 3], 10)
        " [11, 12, 13]

        echo s:L.map_accum('[v:val + v:memo, v:memo + 1]', [1, 2, 3], 10)
        " [11, 13, 15]


        Non-destructive. This does not modify {xs}.

foldl({function}, {init}, {xs})         Vital.Data.List.foldl()
        Reduces the list {xs} using the binary operator {function}, from left
        to right. The starting value of the reduction (typically the
        left-identity of the operator) is {init}.
        Behaves like Haskell's Data.List.foldl().

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

        function! Plus(x, y) abort
          return a:x + a:y
        endfunction

        function! Pair(x, y) abort
          return [a:x, a:y]
        endfunction

        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(function('Plus'), 0, range(1, 10))
        " 55

        echo s:L.foldl(function('Pair'), 0, [1, 2])
        " [[0, 1], 2]

        See also: foldl1, foldr, foldr1
        If you know Haskell, this foldl() is like Haskell's Data.List.foldl
        just for your info.

        Non-destructive. This does not modify {xs}.


foldl1({function}, {xs})                        Vital.Data.List.foldl1()
        Sames Data.List.foldl(), but doesn't take the initial value. Takes
        the first element from {xs} as the initial value.
        Behaves like Haskell's Data.List.foldl1().

        function! Plus(x, y) abort
          return a:x + a:y
        endfunction

        function! Pair(x, y) abort
          return [a:x, a:y]
        endfunction

        echo s:L.foldl1('v:memo + v:val', range(1, 10))
        " 55
        echo s:L.foldl1(function('Plus'), range(1, 10))
        " 55
        echo s:L.foldl1(function('Pair'), [0, 1, 2])
        " [[0, 1], 2]


        Non-destructive. This does not modify {xs}.

foldr({function}, {init}, {xs})         Vital.Data.List.foldr()
        Reduces the list {xs} using the binary operator {function}, from right
        to left. The starting value of the reduction (typically the
        right-identity of the operator) is {init}.
        Behaves like Haskell's Data.List.foldr().

        function! Plus(x, y) abort
          return a:x + a:y
        endfunction

        function! Pair(x, y) abort
          return [a:x, a:y]
        endfunction

        echo s:L.foldr('v:val + v:memo', 0, range(1, 10))
        " 55

        echo s:L.foldr(function('Plus'), 0, range(1, 10))
        " 55

        echo s:L.foldr(function('Pair'), [], [1, 2])
        " [1, [2, []]]


        Non-destructive. This does not modify {xs}.

foldr1({function}, {xs})                        Vital.Data.List.foldr1()
        Sames Data.List.foldr(), but doesn't take the initial value. Takes
        the last element from {xs} as the initial value.
        Behaves like Haskell's Data.List.foldr1().

        function! Plus(x, y) abort
          return a:x + a:y
        endfunction

        function! Pair(x, y) abort
          return [a:x, a:y]
        endfunction

        echo s:L.foldr1('v:val + v:memo', range(1, 10))
        " 55

        echo s:L.foldr1(function('Plus'), range(1, 10))
        " 55

        echo s:L.foldr1(function('Pair'), [1, 2, []])
        " [1, [2, []]]


        Non-destructive. This does not modify {xs}.

count({f}, {xs})                                Vital.Data.List.count()
        NOTE: This is different to Vim script's native count() function.
        NOTE: This is experimental. Unlike other Data.List functions, you
        can't provide a string represated pseudo function to {f}.

        Returns number of items in {xs} that satisfies the given predicate
        function {f}.

        echo s:L.count({ x -> x == 2 }, [1, 2, 3, 4, 5])
        "=> 1

        echo s:L.count({ x -> x % 2 == 0 }, [1, 2, 3, 4, 5])
        "=> 2

        function! s:f(x)
          return a:x % 2 == 0
        endfunction
        echo s:L.count(function('s:f', [1, 2, 3, 4, 5])
        "=> 2

        It scans from left to right. O(n).

        Non-destructive. This does not modify {xs}.

zip(...)                                Vital.Data.List.zip()
        Unifies lists in parallel. If the length of the lists is different,
        adjusts for shorter list, longer list is sliced.
        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]]


        Non-destructive. This does not modify {xs}.

zip_fill({list}, {list}, {elem})        Vital.Data.List.zip_fill()
        Similar to Vital.Data.List.zip(), but goes until the longer one.

        echo s:L.zip_fill([1, 2, 3, 10, 20], [4, 5, 6], 100)
        " [[1, 4], [2, 5], [3, 6], [10, 100], [20, 100]]
        echo s:L.zip_fill([1, 2, 3], [4, 5, 6, 10, 20], 200)
        " [[1, 4], [2, 5], [3, 6], [200, 10], [200, 20]]


        Non-destructive. This does not modify {xs}.

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


        Non-destructive. This does not modify {xs}.

find({list}, {default}, {function})                      Vital.Data.List.find()
        Returns the first value in {list} where the given {function} is
        satisfied. {default} is returned when no item satisfies {function}.
        {function} 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.

        Non-destructive. This does not modify {xs}.


                                        Vital.Data.List.find_index()
find_index({list}, {function} [, {start} [, {default}]])
        Returns the lowest index in {list} where the given {function} 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 {function}. If {default}
        is omitted, -1 is used.

        function! Odd(x) abort
          return a:x % 2 == 1
        endfunction

        echo s:L.find_index([0, 1, 2, 3], 'v:val % 2 == 1')
        " 1
        echo s:L.find_index([0, 1, 2, 3], function('Odd'))
        " 1
        echo s:L.find_index([0, 1, 2, 3], 'v:val > 10')
        " -1

        echo s:L.find_index([0, 1, 2, 3], 'v:val % 2 == 1', 1)
        " 2

        let default_val = -10
        let constant_false_expr = '0'
        echo s:L.find_index([0, 1, 2, 3], constant_false_expr, 0, default_val)
        " -10


        Non-destructive. This does not modify {xs}.

                                        Vital.Data.List.find_last_index()
find_last_index({list}, {function} [, {start} [, {default}]])
        Similar to find_index but this returns the highest index.
        Traversing is done in reverse order.

        function! Odd(x) abort
          return a:x % 2 == 1
        endfunction

        echo s:L.find_last_index([0, 1, 2, 3], 'v:val % 2 == 1')
        " 3
        echo s:L.find_last_index([0, 1, 2, 3], function('Odd'))
        " 3


        Non-destructive. This does not modify {xs}.

                                        Vital.Data.List.find_indices()
find_indices({list}, {function} [, {start}])
        Similar to find_index but this returns all of indices specifying
        {function}.
        When no indices found, empty list is returned.

        function! Odd(x) abort
          return a:x % 2 == 1
        endfunction

        echo s:L.find_indices([0, 1, 2, 3], 'v:val % 2 == 1')
        " [1, 3]
        echo s:L.find_indices([0, 1, 2, 3], function('Odd'))
        " [1, 3]

        echo s:L.find_indices([0, 1, 2, 3], 'v:val > 10')
        " []

        echo s:L.find_indices([0, 1, 2, 3], 'v:val % 2 == 1', 2)
        " [3]
        echo s:L.find_indices([0, 1, 2, 3], 'v:val % 2 == 1', 1)
        " [1, 3]
        echo s:L.find_indices([0, 1, 2, 3], 'v:val % 2 == 1', -2)
        " [3]


        Non-destructive. This does not modify {xs}.

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


        Non-destructive. This does not modify {xs}.


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'])
        " []


        Non-destructive. This does not modify {xs}.

group_by({list}, {function})            Vital.Data.List.group_by()
        Returns a Dictionary grouped by the result of {function}.
        "v:val" can be used in {function} if {function} is a string expression.

        echo s:L.group_by(['a', 'b', 'ab'], 'len(v:val)')
        " {'1': ['a', 'b'], '2': ['ab']}
        echo s:L.group_by(['a', 'b', 'ab'], function('len'))
        " {'1': ['a', 'b'], '2': ['ab']}

        echo s:L.group_by(['a', 'b', 'ab'], 'v:val[0]')
        " {'a': ['a', 'ab'], 'b': ['b']}


        Non-destructive. This does not modify {xs}.

                                        Vital.Data.List.binary_search()
binary_search({list}, {target}, [{func}, [{dict}]])
        Returns the index in {list} where the item has a value equal to
        {target} by binary search.  {list} must be sorted.  If {target} 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


        Non-destructive. This does not modify {xs}.

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]]


        Non-destructive. This does not modify {xs}.

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]]


        Non-destructive. This does not modify {xs}.

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]]


        Non-destructive. This does not modify {xs}.

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

top - main help file - tag index