1

I am aware of lists and dictionaries in vim. But are sets supported in VIM to store only unique values? Or do I just have to use a dictionary with some dummy value?

3

No, there is no datatype Set. So you have to implement it yourself or maybe find some implementation on the net.

If you implement it yourself, you might consider "Dictionary functions" (see :help Dictionary-function) or "numbered functions" (see :help numbered-function).

Here is a quick hack. Maybe you can start from this. Note: This "Set" can only handle strings or numbers.

function! NewSet()
    let newSet = {'dict': {} }

    " number of elements in set
    function! newSet.len()
        return len(self.dict)
    endfunction

    " adds element to set
    " returns 1 if element was added, 0 if it was already present
    function! newSet.add(element)
        if ! has_key(self.dict, a:element)
            let self.dict[a:element] = 1
            return 1
        else
            return 0
        endif
    endfunction

    " returns 1 if element is contained in set
    function! newSet.contains(element)
        return has_key(self.dict, a:element)
    endfunction

    " removes element from set
    " returns 1 if element was removed, 0 if it was not present
    function! newSet.remove(element)
        if(self.contains(a:element))
            call remove(self.dict, a:element)
            return 1
        else
            return 0
        endif
    endfunction

    " returns content as list
    function! newSet.as_list()
        return keys(self.dict)
    endfunction

    return newSet
endfunction

" TEST

let mySet = NewSet()

echo "Add Vim: " . mySet.add("Vim")
echo "Add Vim 2: " . mySet.add("Vim")

echo "Add NeoVim: " . mySet.add("NeoVim")

echo "Contains Vim: " . mySet.contains("Vim")
echo "Contains NeoVim: " . mySet.contains("NeoVim")
echo "Content: " . string(mySet.as_list())
echo "Len: " . string(mySet.len())
echo "Remove Vim: " . mySet.remove("Vim")
echo "Remove Vim 2: " . mySet.remove("Vim")
echo "Contains Vim: " . mySet.contains("Vim")
echo "Content: " . string(mySet.as_list())
echo "Len: " . string(mySet.len())
echo "Remove UNKNOWN: " . mySet.remove("UNKNOWN")

Update

I reconsidered my answer and came to the conclusion, that my previous example implementation has a drawback. Whenever you create a new Set, the functions are added as anonymous (aka numbered) functions. So if you create two sets, all functions are parsed two times and defined two times.

The better solution is to define the functions once and just add the function-references to the Set implementation.

So I would recommend this updated implementation:

" number of elements in set
function! s:len() dict
    return len(self.dict)
endfunction

" adds element to set
" returns 1 if element was added, 0 if it was already present
function! s:add(element) dict
    if ! has_key(self.dict, a:element)
        let self.dict[a:element] = 1
        return 1
    else
        return 0
    endif
endfunction

" returns 1 if element is contained in set
function! s:contains(element) dict
    return has_key(self.dict, a:element)
endfunction

" removes element from set
" returns 1 if element was removed, 0 if it was not present
function! s:remove(element) dict
    if(self.contains(a:element))
        call remove(self.dict, a:element)
        return 1
    else
        return 0
    endif
endfunction

" returns content as list
function! s:as_list() dict
    return keys(self.dict)
endfunction

function! NewSet()
    let newSet = {'dict': {},
                \ 'len': function("s:len"),
                \ 'add': function("s:add"),
                \ 'contains': function("s:contains"),
                \ 'remove': function("s:remove"),
                \ 'as_list': function("s:as_list"),
                \ }
    return newSet
endfunction

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.