updated for version 7.4.218 v7.4.218
authorBram Moolenaar <Bram@vim.org>
Tue, 25 Mar 2014 17:24:23 +0000 (18:24 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 25 Mar 2014 17:24:23 +0000 (18:24 +0100)
Problem:    It's not easy to remove duplicates from a list.
Solution:   Add the uniq() function. (LCD)

runtime/doc/change.txt
runtime/doc/eval.txt
runtime/doc/version7.txt
src/eval.c
src/testdir/test55.in
src/testdir/test55.ok
src/version.c

index d6daf50d44c5ebfcfcd4bd6afdb373ede622d623..da981c4836f60719d8a13cbe9f8bf53c2866b0ca 100644 (file)
@@ -1650,7 +1650,7 @@ And a few warnings:
 7. Sorting text                                                *sorting*
 
 Vim has a sorting function and a sorting command.  The sorting function can be
-found here: |sort()|.
+found here: |sort()|, |uniq()|.
 
                                                        *:sor* *:sort*
 :[range]sor[t][!] [i][u][r][n][x][o] [/{pattern}/]
index 661832d124963612e1d348ece21b5e052125c8d2..56585d1badf21a60f23c0b33de7a6ce2953a4982 100644 (file)
@@ -327,6 +327,7 @@ examples: >
 Changing the order of items in a list: >
        :call sort(list)                " sort a list alphabetically
        :call reverse(list)             " reverse the order of items
+       :call uniq(sort(list))          " sort and remove duplicates
 
 
 For loop ~
@@ -2005,6 +2006,8 @@ trunc( {expr})                    Float   truncate Float {expr}
 type( {name})                  Number  type of variable {name}
 undofile( {name})              String  undo file name for {name}
 undotree()                     List    undo file tree
+uniq( {list} [, {func} [, {dict}]])
+                               List    remove adjacent duplicates from a list
 values( {dict})                        List    values in {dict}
 virtcol( {expr})               Number  screen column of cursor or mark
 visualmode( [expr])            String  last visual mode used
@@ -5488,20 +5491,26 @@ sinh({expr})                                            *sinh()*
 
 
 sort({list} [, {func} [, {dict}]])                     *sort()* *E702*
-               Sort the items in {list} in-place.  Returns {list}.  If you
-               want a list to remain unmodified make a copy first: >
+               Sort the items in {list} in-place.  Returns {list}.
+               
+               If you want a list to remain unmodified make a copy first: >
                        :let sortedlist = sort(copy(mylist))
 <              Uses the string representation of each item to sort on.
                Numbers sort after Strings, |Lists| after Numbers.
                For sorting text in the current buffer use |:sort|.
+
                When {func} is given and it is one then case is ignored.
-               {dict} is for functions with the "dict" attribute.  It will be
-               used to set the local variable "self". |Dictionary-function|
                When {func} is a |Funcref| or a function name, this function
                is called to compare items.  The function is invoked with two
                items as argument and must return zero if they are equal, 1 or
                bigger if the first one sorts after the second one, -1 or
                smaller if the first one sorts before the second one.
+
+               {dict} is for functions with the "dict" attribute.  It will be
+               used to set the local variable "self". |Dictionary-function|
+
+               Also see |uniq()|.
+
                Example: >
                        func MyCompare(i1, i2)
                           return a:i1 == a:i2 ? 0 : a:i1 > a:i2 ? 1 : -1
@@ -6169,6 +6178,14 @@ undotree()                                               *undotree()*
                                blocks.  Each item may again have an "alt"
                                item.
 
+uniq({list} [, {func} [, {dict}]])                     *uniq()* *E882*
+               Remove second and succeeding copies of repeated adjacent
+               {list} items in-place.  Returns {list}.  If you want a list
+               to remain unmodified make a copy first: >
+                       :let newlist = uniq(copy(mylist))
+<              The default compare function uses the string representation of
+               each item.  For the use of {func} and {dict} see |sort()|.
+
 values({dict})                                         *values()*
                Return a |List| with all the values of {dict}.  The |List| is
                in arbitrary order.
index ab4e385e89b910d1694983e69cbc6b9944735966..1bff5b5da92b23894f4b4dcb7642a35b3e91e1fb 100644 (file)
@@ -942,6 +942,7 @@ New and extended functions: ~
 |tagfiles()|           List with tags file names
 |taglist()|            get list of matching tags (Yegappan Lakshmanan)
 |tr()|                 translate characters (Ron Aaron)
+|uniq()|               remove copies of repeated adjacent list items
 |values()|             get List of Dictionary values
 |winnr()|              takes an argument: what window to use
 |winrestview()|                restore the view of the current window
index 12794d4cbd4020b94250eba244c6f043e234d177..baaa12f01572000baab96111cf20464df5313a4a 100644 (file)
@@ -744,6 +744,7 @@ static void f_trunc __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_type __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_undofile __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_undotree __ARGS((typval_T *argvars, typval_T *rettv));
+static void f_uniq __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_values __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_virtcol __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_visualmode __ARGS((typval_T *argvars, typval_T *rettv));
@@ -8150,6 +8151,7 @@ static struct fst
     {"type",           1, 1, f_type},
     {"undofile",       1, 1, f_undofile},
     {"undotree",       0, 0, f_undotree},
+    {"uniq",           1, 3, f_uniq},
     {"values",         1, 1, f_values},
     {"virtcol",                1, 1, f_virtcol},
     {"visualmode",     0, 1, f_visualmode},
@@ -17023,10 +17025,11 @@ static int    item_compare_ic;
 static char_u  *item_compare_func;
 static dict_T  *item_compare_selfdict;
 static int     item_compare_func_err;
+static void    do_sort_uniq __ARGS((typval_T *argvars, typval_T *rettv, int sort));
 #define ITEM_COMPARE_FAIL 999
 
 /*
- * Compare functions for f_sort() below.
+ * Compare functions for f_sort() and f_uniq() below.
  */
     static int
 #ifdef __BORLANDC__
@@ -17100,9 +17103,10 @@ item_compare2(s1, s2)
  * "sort({list})" function
  */
     static void
-f_sort(argvars, rettv)
+do_sort_uniq(argvars, rettv, sort)
     typval_T   *argvars;
     typval_T   *rettv;
+    int                sort;
 {
     list_T     *l;
     listitem_T *li;
@@ -17111,12 +17115,12 @@ f_sort(argvars, rettv)
     long       i;
 
     if (argvars[0].v_type != VAR_LIST)
-       EMSG2(_(e_listarg), "sort()");
+       EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
     else
     {
        l = argvars[0].vval.v_list;
        if (l == NULL || tv_check_lock(l->lv_lock,
-                                            (char_u *)_("sort() argument")))
+              (char_u *)(sort ? _("sort() argument") : _("uniq() argument"))))
            return;
        rettv->vval.v_list = l;
        rettv->v_type = VAR_LIST;
@@ -17163,29 +17167,72 @@ f_sort(argvars, rettv)
        ptrs = (listitem_T **)alloc((int)(len * sizeof(listitem_T *)));
        if (ptrs == NULL)
            return;
+
        i = 0;
-       for (li = l->lv_first; li != NULL; li = li->li_next)
-           ptrs[i++] = li;
+       if (sort)
+       {
+           /* sort(): ptrs will be the list to sort */
+           for (li = l->lv_first; li != NULL; li = li->li_next)
+               ptrs[i++] = li;
 
-       item_compare_func_err = FALSE;
-       /* test the compare function */
-       if (item_compare_func != NULL
-               && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
+           item_compare_func_err = FALSE;
+           /* test the compare function */
+           if (item_compare_func != NULL
+                   && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
                                                         == ITEM_COMPARE_FAIL)
-           EMSG(_("E702: Sort compare function failed"));
+               EMSG(_("E702: Sort compare function failed"));
+           else
+           {
+               /* Sort the array with item pointers. */
+               qsort((void *)ptrs, (size_t)len, sizeof(listitem_T *),
+                   item_compare_func == NULL ? item_compare : item_compare2);
+
+               if (!item_compare_func_err)
+               {
+                   /* Clear the List and append the items in sorted order. */
+                   l->lv_first = l->lv_last = l->lv_idx_item = NULL;
+                   l->lv_len = 0;
+                   for (i = 0; i < len; ++i)
+                       list_append(l, ptrs[i]);
+               }
+           }
+       }
        else
        {
-           /* Sort the array with item pointers. */
-           qsort((void *)ptrs, (size_t)len, sizeof(listitem_T *),
-                   item_compare_func == NULL ? item_compare : item_compare2);
+           int (*item_compare_func_ptr)__ARGS((const void *, const void *));
+
+           /* f_uniq(): ptrs will be a stack of items to remove */
+           item_compare_func_err = FALSE;
+           item_compare_func_ptr = item_compare_func
+                                              ? item_compare2 : item_compare;
+
+           for (li = l->lv_first; li != NULL && li->li_next != NULL;
+                                                            li = li->li_next)
+           {
+               if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
+                                                                        == 0)
+                   ptrs[i++] = li;
+               if (item_compare_func_err)
+               {
+                   EMSG(_("E882: Uniq compare function failed"));
+                   break;
+               }
+           }
 
            if (!item_compare_func_err)
            {
-               /* Clear the List and append the items in the sorted order. */
-               l->lv_first = l->lv_last = l->lv_idx_item = NULL;
-               l->lv_len = 0;
-               for (i = 0; i < len; ++i)
-                   list_append(l, ptrs[i]);
+               while (--i >= 0)
+               {
+                   li = ptrs[i]->li_next;
+                   ptrs[i]->li_next = li->li_next;
+                   if (li->li_next != NULL)
+                       li->li_next->li_prev = ptrs[i];
+                   else
+                       l->lv_last = ptrs[i];
+                   list_fix_watch(l, li);
+                   listitem_free(li);
+                   l->lv_len--;
+               }
            }
        }
 
@@ -17193,6 +17240,28 @@ f_sort(argvars, rettv)
     }
 }
 
+/*
+ * "sort({list})" function
+ */
+    static void
+f_sort(argvars, rettv)
+    typval_T   *argvars;
+    typval_T   *rettv;
+{
+    do_sort_uniq(argvars, rettv, TRUE);
+}
+
+/*
+ * "uniq({list})" function
+ */
+    static void
+f_uniq(argvars, rettv)
+    typval_T   *argvars;
+    typval_T   *rettv;
+{
+    do_sort_uniq(argvars, rettv, FALSE);
+}
+
 /*
  * "soundfold({word})" function
  */
index 4b20de403f5151dc4b72c5826e26d76124f34b0f..85a8063774d143b1b552ce5824cd1816f4b42ce2 100644 (file)
@@ -323,13 +323,15 @@ let l = [0, 1, 2, 3]
 :  $put ='caught ' . v:exception
 :endtry
 :"
-:" reverse() and sort()
-:let l = ['-0', 'A11', 2, 'xaaa', 4, 'foo', 'foo6', [0, 1, 2], 'x8']
+:" reverse(), sort(), uniq()
+:let l = ['-0', 'A11', 2, 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5]
+:$put =string(uniq(copy(l)))
 :$put =string(reverse(l))
 :$put =string(reverse(reverse(l)))
 :$put =string(sort(l))
 :$put =string(reverse(sort(l)))
 :$put =string(sort(reverse(sort(l))))
+:$put =string(uniq(sort(l)))
 :"
 :" splitting a string to a List
 :$put =string(split('  aa  bb '))
index 396c9bed19523166cb8b854a48231efd926333e7..be476e8e939ef0ca0f3cc2f41dd7b4e7276a99d0 100644 (file)
@@ -94,11 +94,13 @@ caught a:000[0]
 caught a:000[2]
 caught a:000[3]
 [1, 2, [3, 9, 5, 6], {'a': 12, '5': 8}]
-['x8', [0, 1, 2], 'foo6', 'foo', 4, 'xaaa', 2, 'A11', '-0']
-['x8', [0, 1, 2], 'foo6', 'foo', 4, 'xaaa', 2, 'A11', '-0']
-['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 2, 4, [0, 1, 2]]
-[[0, 1, 2], 4, 2, 'xaaa', 'x8', 'foo6', 'foo', 'A11', '-0']
-['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 2, 4, [0, 1, 2]]
+['-0', 'A11', 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5]
+[1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0']
+[1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0']
+['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]]
+[[0, 1, 2], [0, 1, 2], 4, 2, 2, 1.5, 'xaaa', 'x8', 'foo6', 'foo', 'foo', 'A11', '-0']
+['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]]
+['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 4, [0, 1, 2]]
 ['aa', 'bb']
 ['aa', 'bb']
 ['', 'aa', 'bb', '']
index ce4659c6af907d8807a3943e2df1d85369aee42e..e5e75fbec9d23d3fd8cdfe4ac7c0da7d88058103 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    218,
 /**/
     217,
 /**/