from lines to dict keys

1 view
Skip to first unread message

Marc Chantreux

unread,
Nov 9, 2009, 4:52:31 AM11/9/09
to v...@vim.org
hello guys,

i want each lines of the output of a shell command to become a key of a
dict. I wote this code:

let t = {}
for k in split( system("echo foo; echo bar "), '\n' )
let t[k] = 1
endfor

but i don't like it: as the loop is here to populate the dictionnary, i
would like to use something more appropriate. In perl for exemple, the
map function enables you to write

my %a = map { $_ => 1 } split /\n/, qx< echo foo; echo bar>

vim has the equivalent of $_: it's called v:val, so i tried to use map
or filter with attempts looking like that:

let t = map( split( system("echo foo; echo bar "), '\n' ), { v:val : 1 } )

and yet i just wonder if it's possible.

regards,
marc

Andy Wokula

unread,
Nov 9, 2009, 12:33:24 PM11/9/09
to vim...@googlegroups.com
Marc Chantreux schrieb:

It is possible, the second argument to map() must be a string:
:h map()
:let t = map(["foo", "bar"], '{v:val : 1}')

--
Andy

Marc Chantreux

unread,
Nov 9, 2009, 7:30:26 PM11/9/09
to vim...@googlegroups.com
hello Andy and thanks for reply.

On Mon, Nov 09, 2009 at 06:33:24PM +0100, Andy Wokula wrote:
> It is possible, the second argument to map() must be a string:
> :h map()
> :let t = map(["foo", "bar"], '{v:val : 1}')

i tried this solution but the result is

[{'foo': 1}, {'bar': 1}]

when i expect

{'foo': 1, 'bar': 1 }

regards

marc

Andy Wokula

unread,
Nov 10, 2009, 6:19:19 AM11/10/09
to vim...@googlegroups.com
Marc Chantreux schrieb:

Sorry, I didn't understand (dunno Perl).
I think you can't do it so nicely in Vim, but you can try the
following:

" helper to keep the list unchanged (not required):
func! KeepVal(_)
return v:val
endfunc

let in_list = ["foo", "bar"]
let out_dict = {}
call map(in_list, 'KeepVal(extend(out_dict, {v:val : 1}))')

" not so nice:
" - extra command for initialising out_dict
" - return value of map() is useless here

--
Andy

Christian Brabandt

unread,
Nov 10, 2009, 6:26:34 AM11/10/09
to vim...@googlegroups.com
On Tue, November 10, 2009 12:19 pm, Andy Wokula wrote:
> Sorry, I didn't understand (dunno Perl).
> I think you can't do it so nicely in Vim, but you can try the
> following:
>
> " helper to keep the list unchanged (not required):
> func! KeepVal(_)
> return v:val
> endfunc
>
> let in_list = ["foo", "bar"]
> let out_dict = {}
> call map(in_list, 'KeepVal(extend(out_dict, {v:val : 1}))')

You don't need KeepVal():
:call map(copy(in_list), 'extend(out_dict, {v:val : 1})')

regards,
Christian

Andy Wokula

unread,
Nov 10, 2009, 6:41:55 AM11/10/09
to vim...@googlegroups.com
Christian Brabandt schrieb:

I just didn't like getting a list full of dict references. And the
return value of map() will be less "junky".

--
Andy

Christian Brabandt

unread,
Nov 10, 2009, 6:55:26 AM11/10/09
to vim...@googlegroups.com
Hi Andy!

Okay, how about

:let @_=string(map(copy(in_list), 'extend(out_dict, {v:val : 1})'))

regards,
Christian
--
• EFI is this other Intel brain-damage (the first one being ACPI).
Torvalds, Linus (2006-07-24).

Tom Link

unread,
Nov 10, 2009, 7:24:04 AM11/10/09
to vim_use
> :let @_=string(map(copy(in_list), 'extend(out_dict, {v:val : 1})'))

I personally don't think it is a good idea to use map for iterating
over a list since it manipulates the list it is working on and returns
that transformed list.

Since vimscripts provides no high-order function to iterate over a
list without modifying it, what's wrong with a dull looking for-loop:

for k in list
let dict[k] = 1
endfor

Tom Link

unread,
Nov 10, 2009, 7:30:54 AM11/10/09
to vim_use
> what's wrong with a dull looking for-loop:

Okay, that was the original solution anyway. I'd say stick to it.

Andy Wokula

unread,
Nov 10, 2009, 7:38:36 AM11/10/09
to vim...@googlegroups.com
Tom Link schrieb:

Nothing, it's the best option ;) But the OP already used that.

--
Andy

Tom Link

unread,
Nov 10, 2009, 7:39:29 AM11/10/09
to vim_use
On 10 Nov., 13:30, Tom Link <micat...@gmail.com> wrote:
> > what's wrong with a dull looking for-loop:
>
> Okay, that was the original solution anyway. I'd say stick to it.

Sorry for the reply to self. If you really want to use map, you could
use:

exec 'let dict = {'. join(map(split(lines, "\n"), 'string(v:val) .":
1"'), ",") .'}'

You have to make sure the lines are unique.

Marc Chantreux

unread,
Nov 10, 2009, 11:06:14 AM11/10/09
to vim...@googlegroups.com
hello all

many thanks for you tries and replies. all of them where very
instructive.

i'll stick on the for-loop solution as it seems that functionnal
solutions are harder to read/debug in viml.

regards
marc

Hari Krishna Dara

unread,
Nov 11, 2009, 1:11:46 AM11/11/09
to vim...@googlegroups.com
Since you seem to want a one liner, here is one:

let t=eval('{'.join(map(split(system("echo foo; echo bar"), "\n" ),
'"''".v:val."'': 1"'), ',').'}')

--
Hari
>
> regards
> marc
>
> >
>

Marc Chantreux

unread,
Nov 11, 2009, 5:41:51 AM11/11/09
to vim...@googlegroups.com
hello Hari


On Tue, Nov 10, 2009 at 10:11:46PM -0800, Hari Krishna Dara wrote:
> Since you seem to want a one liner, here is one:
>
> let t=eval('{'.join(map(split(system("echo foo; echo bar"), "\n" ),
> '"''".v:val."'': 1"'), ',').'}')

I want my code to be readable then short. it seems that viml isn't the
good langage for it. I stick on the for-loop :)

regards,
marc

Reply all
Reply to author
Forward
0 new messages