I've been noticing a flaw in my workflow when I'm editing a lot of buffers: I am on a buffer and I want to switch to another one of which I don't remember the name and which isn't the alternative buffer. So using :b# is not possible and using the completion with the command :b isn't convenient neither.
On the contrary, I find tab-completion to be extremely convenient. Setting the right options to values that work for you may help a lot. These are the relevant lines from my vimrc (they work for me but they may not work for you so don't just copy them):
nnoremap ,b :buffer *
set wildmenu
set wildignore+=*.swp,*.bak
set wildignore+=*.pyc,*.class,*.sln,*.Master,*.csproj,*.csproj.user,*.cache,*.dll,*.pdb,*.min.*
set wildignore+=*/.git/**/*,*/.hg/**/*,*/.svn/**/*
set wildignore+=*/min/*,*/vendor/*,*/node_modules/*,*/bower_components/*
set wildignore+=tags,cscope.*
set wildignore+=*.tar.*
set wildignorecase
set wildmode=full
With that, the right buffer is rarely more than five or six keystrokes away:

This give me a command :B (and a mapping) which calls the function :buffers wait for an input and finally calls :b followed by the input.
Barry Arthur came up with a much simpler solution years ago that has become quite popular since then:
nnoremap <leader>b :ls<CR>:b<Space>
of which I proposed a slightly more versatile variant a couple years ago:
nnoremap gb :ls<CR>:b

Since we are talking vimscript, here is a nice little function I wrote that "auto-populates" the command-line with the right command stub after list-like commands like :ls or :ilist. The advantage of that function over the mappings above is that I don't have to remember specific mappings. It works just like Vim, but with a little twist.
" smooth listing
cnoremap <expr> <CR> <SID>CCR()
function! s:CCR()
if getcmdtype() == ":"
let cmdline = getcmdline()
if cmdline =~ '\v\C^(dli|il)' | return "\<CR>:" . cmdline[0] . "jump " . split(cmdline, " ")[1] . "\<S-Left>\<Left>"
elseif cmdline =~ '\v\C^(cli|lli)' | return "\<CR>:silent " . repeat(cmdline[0], 2) . "\<Space>"
elseif cmdline =~ '\C^changes' | set nomore | return "\<CR>:sil se more|norm! g;\<S-Left>"
elseif cmdline =~ '\C^ju' | set nomore | return "\<CR>:sil se more|norm! \<C-o>\<S-Left>"
elseif cmdline =~ '\C^ol' | set nomore | return "\<CR>:sil se more|e #<"
elseif cmdline =~ '\C^undol' | return "\<CR>:u "
elseif cmdline =~ '\C^ls' | return "\<CR>:b"
elseif cmdline =~ '/#$' | return "\<CR>:"
else | return "\<CR>" | endif
else | return "\<CR>" | endif
endfunction

That said, I'm a big proponent of "symbol-based navigation" over "file-based navigation". When applicable, symbol-based navigation is much faster and much more economic than file-based navigation.
The last GIF shows one mean of symbol-based navigation, by the way. The example is silly but… oh well.
:lsfollowed by:b#(don't need to hit return or escape first, can go directly from the buffer list in 'ls'.) (Posting as comment because it doesn't seem substantial enough to be an answer? Also wondering if I'm missing something and answering the wrong question.) – LindaJeanne Aug 11 '16 at 13:49:b#is not what I'm looking for but yeah the fact that you can save a keystroke by entering directly:bwithout pressingenterbefore is interesting. (Indeed that is maybe too light to be an answer, but it was worth a comment :-) ) – statox Aug 11 '16 at 13:54#character as a stand-in for a (buffer) number, rather than the literal#character. – 8bittree Oct 05 '16 at 20:43