forked from aniani/vim
patch 8.2.0878: no reduce() function
Problem: No reduce() function. Solution: Add a reduce() function. (closes #5481)
This commit is contained in:
parent
e8f5ec0d30
commit
85629985b7
@ -2679,6 +2679,8 @@ readdir({dir} [, {expr}]) List file names in {dir} selected by {expr}
|
||||
readdirex({dir} [, {expr}]) List file info in {dir} selected by {expr}
|
||||
readfile({fname} [, {type} [, {max}]])
|
||||
List get list of lines from file {fname}
|
||||
reduce({object}, {func} [, {initial}])
|
||||
any reduce {object} using {func}
|
||||
reg_executing() String get the executing register name
|
||||
reg_recording() String get the recording register name
|
||||
reltime([{start} [, {end}]]) List get time value
|
||||
@ -7965,6 +7967,26 @@ readfile({fname} [, {type} [, {max}]])
|
||||
Can also be used as a |method|: >
|
||||
GetFileName()->readfile()
|
||||
|
||||
reduce({object}, {func} [, {initial}]) *reduce()* *E998*
|
||||
{func} is called for every item in {object}, which can be a
|
||||
|List| or a |Blob|. {func} is called with two arguments: the
|
||||
result so far and current item. After processing all items
|
||||
the result is returned.
|
||||
|
||||
{initial} is the initial result. When omitted, the first item
|
||||
in {object} is used and {func} is first called for the second
|
||||
item. If {initial} is not given and {object} is empty no
|
||||
result can be computed, an E998 error is given.
|
||||
|
||||
Examples: >
|
||||
echo reduce([1, 3, 5], { acc, val -> acc + val })
|
||||
echo reduce(['x', 'y'], { acc, val -> acc .. val }, 'a')
|
||||
echo reduce(0z1122, { acc, val -> 2 * acc + val })
|
||||
<
|
||||
Can also be used as a |method|: >
|
||||
echo mylist->reduce({ acc, val -> acc + val }, 0)
|
||||
|
||||
|
||||
reg_executing() *reg_executing()*
|
||||
Returns the single letter name of the register being executed.
|
||||
Returns an empty string when no register is being executed.
|
||||
|
@ -769,6 +769,7 @@ static funcentry_T global_functions[] =
|
||||
{"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir},
|
||||
{"readdirex", 1, 2, FEARG_1, ret_list_dict_any, f_readdirex},
|
||||
{"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
|
||||
{"reduce", 2, 3, FEARG_1, ret_any, f_reduce},
|
||||
{"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
|
||||
{"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
|
||||
{"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
|
||||
|
@ -1690,6 +1690,7 @@ EXTERN char e_inval_string[] INIT(= N_("E908: using an invalid value as a String
|
||||
EXTERN char e_const_option[] INIT(= N_("E996: Cannot lock an option"));
|
||||
EXTERN char e_unknown_option[] INIT(= N_("E113: Unknown option: %s"));
|
||||
EXTERN char e_letunexp[] INIT(= N_("E18: Unexpected characters in :let"));
|
||||
EXTERN char e_reduceempty[] INIT(= N_("E998: Reduce of an empty %s with no initial value"));
|
||||
#endif
|
||||
#ifdef FEAT_QUICKFIX
|
||||
EXTERN char e_readerrf[] INIT(= N_("E47: Error while reading errorfile"));
|
||||
|
105
src/list.c
105
src/list.c
@ -2305,4 +2305,109 @@ f_reverse(typval_T *argvars, typval_T *rettv)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* "reduce(list, { accumlator, element -> value } [, initial])" function
|
||||
*/
|
||||
void
|
||||
f_reduce(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
typval_T accum;
|
||||
char_u *func_name;
|
||||
partial_T *partial = NULL;
|
||||
funcexe_T funcexe;
|
||||
typval_T argv[3];
|
||||
|
||||
if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB)
|
||||
{
|
||||
emsg(_(e_listblobreq));
|
||||
return;
|
||||
}
|
||||
|
||||
if (argvars[1].v_type == VAR_FUNC)
|
||||
func_name = argvars[1].vval.v_string;
|
||||
else if (argvars[1].v_type == VAR_PARTIAL)
|
||||
{
|
||||
partial = argvars[1].vval.v_partial;
|
||||
func_name = partial_name(partial);
|
||||
}
|
||||
else
|
||||
func_name = tv_get_string(&argvars[1]);
|
||||
if (*func_name == NUL)
|
||||
return; // type error or empty name
|
||||
|
||||
vim_memset(&funcexe, 0, sizeof(funcexe));
|
||||
funcexe.evaluate = TRUE;
|
||||
funcexe.partial = partial;
|
||||
|
||||
if (argvars[0].v_type == VAR_LIST)
|
||||
{
|
||||
list_T *l = argvars[0].vval.v_list;
|
||||
listitem_T *li = NULL;
|
||||
|
||||
CHECK_LIST_MATERIALIZE(l);
|
||||
if (argvars[2].v_type == VAR_UNKNOWN)
|
||||
{
|
||||
if (l == NULL || l->lv_first == NULL)
|
||||
{
|
||||
semsg(_(e_reduceempty), "List");
|
||||
return;
|
||||
}
|
||||
accum = l->lv_first->li_tv;
|
||||
li = l->lv_first->li_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
accum = argvars[2];
|
||||
if (l != NULL)
|
||||
li = l->lv_first;
|
||||
}
|
||||
|
||||
copy_tv(&accum, rettv);
|
||||
for ( ; li != NULL; li = li->li_next)
|
||||
{
|
||||
argv[0] = accum;
|
||||
argv[1] = li->li_tv;
|
||||
if (call_func(func_name, -1, rettv, 2, argv, &funcexe) == FAIL)
|
||||
return;
|
||||
accum = *rettv;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
blob_T *b = argvars[0].vval.v_blob;
|
||||
int i;
|
||||
|
||||
if (argvars[2].v_type == VAR_UNKNOWN)
|
||||
{
|
||||
if (b == NULL || b->bv_ga.ga_len == 0)
|
||||
{
|
||||
semsg(_(e_reduceempty), "Blob");
|
||||
return;
|
||||
}
|
||||
accum.v_type = VAR_NUMBER;
|
||||
accum.vval.v_number = blob_get(b, 0);
|
||||
i = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
accum = argvars[2];
|
||||
i = 0;
|
||||
}
|
||||
|
||||
copy_tv(&accum, rettv);
|
||||
if (b != NULL)
|
||||
{
|
||||
for ( ; i < b->bv_ga.ga_len; i++)
|
||||
{
|
||||
argv[0] = accum;
|
||||
argv[1].v_type = VAR_NUMBER;
|
||||
argv[1].vval.v_number = blob_get(b, i);
|
||||
if (call_func(func_name, -1, rettv, 2, argv, &funcexe) == FAIL)
|
||||
return;
|
||||
accum = *rettv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(FEAT_EVAL)
|
||||
|
@ -51,4 +51,5 @@ void f_extend(typval_T *argvars, typval_T *rettv);
|
||||
void f_insert(typval_T *argvars, typval_T *rettv);
|
||||
void f_remove(typval_T *argvars, typval_T *rettv);
|
||||
void f_reverse(typval_T *argvars, typval_T *rettv);
|
||||
void f_reduce(typval_T *argvars, typval_T *rettv);
|
||||
/* vim: set ft=c : */
|
||||
|
@ -680,6 +680,37 @@ func Test_reverse_sort_uniq()
|
||||
call assert_fails("call sort([1, 2], function('min'))", "E702:")
|
||||
endfunc
|
||||
|
||||
" reduce a list or a blob
|
||||
func Test_reduce()
|
||||
call assert_equal(1, reduce([], { acc, val -> acc + val }, 1))
|
||||
call assert_equal(10, reduce([1, 3, 5], { acc, val -> acc + val }, 1))
|
||||
call assert_equal(2 * (2 * ((2 * 1) + 2) + 3) + 4, reduce([2, 3, 4], { acc, val -> 2 * acc + val }, 1))
|
||||
call assert_equal('a x y z', ['x', 'y', 'z']->reduce({ acc, val -> acc .. ' ' .. val}, 'a'))
|
||||
call assert_equal(#{ x: 1, y: 1, z: 1 }, ['x', 'y', 'z']->reduce({ acc, val -> extend(acc, { val: 1 }) }, {}))
|
||||
call assert_equal([0, 1, 2, 3], reduce([1, 2, 3], function('add'), [0]))
|
||||
|
||||
let l = ['x', 'y', 'z']
|
||||
call assert_equal(42, reduce(l, function('get'), #{ x: #{ y: #{ z: 42 } } }))
|
||||
call assert_equal(['x', 'y', 'z'], l)
|
||||
|
||||
call assert_equal(1, reduce([1], { acc, val -> acc + val }))
|
||||
call assert_equal('x y z', reduce(['x', 'y', 'z'], { acc, val -> acc .. ' ' .. val }))
|
||||
call assert_equal(120, range(1, 5)->reduce({ acc, val -> acc * val }))
|
||||
call assert_fails("call reduce([], { acc, val -> acc + val })", 'E998: Reduce of an empty List with no initial value')
|
||||
|
||||
call assert_equal(1, reduce(0z, { acc, val -> acc + val }, 1))
|
||||
call assert_equal(1 + 0xaf + 0xbf + 0xcf, reduce(0zAFBFCF, { acc, val -> acc + val }, 1))
|
||||
call assert_equal(2 * (2 * 1 + 0xaf) + 0xbf, 0zAFBF->reduce({ acc, val -> 2 * acc + val }, 1))
|
||||
|
||||
call assert_equal(0xff, reduce(0zff, { acc, val -> acc + val }))
|
||||
call assert_equal(2 * (2 * 0xaf + 0xbf) + 0xcf, reduce(0zAFBFCF, { acc, val -> 2 * acc + val }))
|
||||
call assert_fails("call reduce(0z, { acc, val -> acc + val })", 'E998: Reduce of an empty Blob with no initial value')
|
||||
|
||||
call assert_fails("call reduce({}, { acc, val -> acc + val }, 1)", 'E897:')
|
||||
call assert_fails("call reduce(0, { acc, val -> acc + val }, 1)", 'E897:')
|
||||
call assert_fails("call reduce('', { acc, val -> acc + val }, 1)", 'E897:')
|
||||
endfunc
|
||||
|
||||
" splitting a string to a List using split()
|
||||
func Test_str_split()
|
||||
call assert_equal(['aa', 'bb'], split(' aa bb '))
|
||||
|
@ -746,6 +746,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
878,
|
||||
/**/
|
||||
877,
|
||||
/**/
|
||||
|
Loading…
x
Reference in New Issue
Block a user