Maps and binaries

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Maps and binaries

Bob Cowdery-4
Hi,

Its a long time since using Erlang so just getting back in. I know that
there is always better ways to do things so is there a better patten
matching way than this straight forward step-wise method.
I have output from a UDP request put through jstone:decode which ends up
like so:
#{<<"outputs">> =>
       [#{<<"api">> => <<"MME">>,<<"channels">> => 2,<<"direction">> => 1,
          <<"index">> => 5,<<"name">> => <<"Microsoft Sound Mapper -
Output">>},
        #{<<"api">> => <<"MME">>,<<"channels">> => 8,<<"direction">> => 1,
          <<"index">> => 6,<<"name">> => <<"Speakers (Realtek High
Definiti">>},
...
      #{<<"api">> => <<>>,<<"channels">> => 0,<<"direction">> => 0,
          <<"index">> => 0,<<"name">> => <<>>}]}
I want to extract the second member api and name.

     Map = jsone:decode(Resp),
     List = maps:get(<<"outputs">>, Map),
     Element = lists:nth(2, List),
     Api = my_binary_to_list(maps:get(<<"api">>, Element)),
     Dev = my_binary_to_list(maps:get(<<"name">>, Element)),
     io:format("~p, ~p~n", [Api, Dev]).

my_binary_to_list(<<H,T/binary>>) ->
     [H|my_binary_to_list(T)];
my_binary_to_list(<<>>) -> [].

prints:

"MME", "Speakers (Realtek High Definiti"

Thanks in advance, Bob
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Maps and binaries

Loïc Hoguin-3
Just match directly and let io:format convert for you:

#{<<"outputs">> := [_, #{
     <<"api">> := Api,
     <<"name">> := Dev
}|_]} = jsone:decode(Resp),
io:format("\"~s\", \"~s\"~n", [Api, Dev]).

Or ~ts if it can have Unicode characters.

On 12/12/18 11:24 AM, Bob Cowdery wrote:

> Hi,
>
> Its a long time since using Erlang so just getting back in. I know that
> there is always better ways to do things so is there a better patten
> matching way than this straight forward step-wise method.
> I have output from a UDP request put through jstone:decode which ends up
> like so:
> #{<<"outputs">> =>
>        [#{<<"api">> => <<"MME">>,<<"channels">> => 2,<<"direction">> => 1,
>           <<"index">> => 5,<<"name">> => <<"Microsoft Sound Mapper -
> Output">>},
>         #{<<"api">> => <<"MME">>,<<"channels">> => 8,<<"direction">> => 1,
>           <<"index">> => 6,<<"name">> => <<"Speakers (Realtek High
> Definiti">>},
> ...
>       #{<<"api">> => <<>>,<<"channels">> => 0,<<"direction">> => 0,
>           <<"index">> => 0,<<"name">> => <<>>}]}
> I want to extract the second member api and name.
>
>      Map = jsone:decode(Resp),
>      List = maps:get(<<"outputs">>, Map),
>      Element = lists:nth(2, List),
>      Api = my_binary_to_list(maps:get(<<"api">>, Element)),
>      Dev = my_binary_to_list(maps:get(<<"name">>, Element)),
>      io:format("~p, ~p~n", [Api, Dev]).
>
> my_binary_to_list(<<H,T/binary>>) ->
>      [H|my_binary_to_list(T)];
> my_binary_to_list(<<>>) -> [].
>
> prints:
>
> "MME", "Speakers (Realtek High Definiti"
>
> Thanks in advance, Bob
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

--
Loïc Hoguin
https://ninenines.eu
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Maps and binaries

Hugo Mills-2
In reply to this post by Bob Cowdery-4
   Hi, Bob,

On Wed, Dec 12, 2018 at 10:24:35AM +0000, Bob Cowdery wrote:

> Its a long time since using Erlang so just getting back in. I know
> that there is always better ways to do things so is there a better
> patten matching way than this straight forward step-wise method.
> I have output from a UDP request put through jstone:decode which
> ends up like so:
> #{<<"outputs">> =>
>       [#{<<"api">> => <<"MME">>,<<"channels">> => 2,<<"direction">> => 1,
>          <<"index">> => 5,<<"name">> => <<"Microsoft Sound Mapper -
> Output">>},
>        #{<<"api">> => <<"MME">>,<<"channels">> => 8,<<"direction">> => 1,
>          <<"index">> => 6,<<"name">> => <<"Speakers (Realtek High
> Definiti">>},
> ...
>      #{<<"api">> => <<>>,<<"channels">> => 0,<<"direction">> => 0,
>          <<"index">> => 0,<<"name">> => <<>>}]}
> I want to extract the second member api and name.
>
>     Map = jsone:decode(Resp),
>     List = maps:get(<<"outputs">>, Map),
>     Element = lists:nth(2, List),
>     Api = my_binary_to_list(maps:get(<<"api">>, Element)),
>     Dev = my_binary_to_list(maps:get(<<"name">>, Element)),
>     io:format("~p, ~p~n", [Api, Dev]).
   This seems perfectly reasonable as it is. However, you can
pattern-match maps this way:

   #{<<"outputs">> := List} = Map

and if you know that it's always going to be the second entry in the
list, you can pattern-match that with this:

   [_, Element | _] = List

   Note that with the map pattern, the key must always be either a
literal or a bound variable. Also note the required use of :=, which
is the "mandatory key" syntax, as opposed to =>, which is "optional
key". You can match multiple key/value pairs in a map in a single
pattern.

> my_binary_to_list(<<H,T/binary>>) ->
>     [H|my_binary_to_list(T)];
> my_binary_to_list(<<>>) -> [].

   Why not just use binary_to_list/1 in the erlang module?

   Hugo.

> prints:
>
> "MME", "Speakers (Realtek High Definiti"
>
> Thanks in advance, Bob
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

--
Hugo Mills             | Doughnut furs ache me, Omar Dorlin
hugo@... carfax.org.uk |
http://carfax.org.uk/  |
PGP: E2AB1DE4          |                                            Steve Bell

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

signature.asc (853 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Maps and binaries

Bob Cowdery-4
Hi Hugo

Thanks, all good points. This is test code just sorting out how to do
things. I have a problem with encoding now.

This is my map:

msg(set_audio_route) -> #{<<"cmd">> => <<"set_audio_route">>,
<<"params">> => []};

to which I add parameters and encode.
PMsg = maps:put(<<"params">>, [1, "LOCAL", 1, Api, Dev, "BOTH"],
msg(set_audio_route)),
FullMsg = jsone:encode(PMsg),

This encodes to:

SetRoute -
<<"{\"cmd\":\"set_audio_route\",\"params\":[1,[76,79,67,65,76],1,[77,77,69],[83,112,101,97,107,101,114,115,32,40,82,101,97,108,116,101,107,32,72,105,103,104,32,68,101,102,105,110,105,116,105],[66,79,84,72]]}">>

The problem is my C lib when I decode the Json is expecting strings in
the list and it gets lists. I'm doing this in a few languages at the
moment so can't change the C for one language when its working for
others. Is there a way around this?

Bob)

On 12/12/2018 10:37, Hugo Mills wrote:

>     Hi, Bob,
>
> On Wed, Dec 12, 2018 at 10:24:35AM +0000, Bob Cowdery wrote:
>> Its a long time since using Erlang so just getting back in. I know
>> that there is always better ways to do things so is there a better
>> patten matching way than this straight forward step-wise method.
>> I have output from a UDP request put through jstone:decode which
>> ends up like so:
>> #{<<"outputs">> =>
>>        [#{<<"api">> => <<"MME">>,<<"channels">> => 2,<<"direction">> => 1,
>>           <<"index">> => 5,<<"name">> => <<"Microsoft Sound Mapper -
>> Output">>},
>>         #{<<"api">> => <<"MME">>,<<"channels">> => 8,<<"direction">> => 1,
>>           <<"index">> => 6,<<"name">> => <<"Speakers (Realtek High
>> Definiti">>},
>> ...
>>       #{<<"api">> => <<>>,<<"channels">> => 0,<<"direction">> => 0,
>>           <<"index">> => 0,<<"name">> => <<>>}]}
>> I want to extract the second member api and name.
>>
>>      Map = jsone:decode(Resp),
>>      List = maps:get(<<"outputs">>, Map),
>>      Element = lists:nth(2, List),
>>      Api = my_binary_to_list(maps:get(<<"api">>, Element)),
>>      Dev = my_binary_to_list(maps:get(<<"name">>, Element)),
>>      io:format("~p, ~p~n", [Api, Dev]).
>     This seems perfectly reasonable as it is. However, you can
> pattern-match maps this way:
>
>     #{<<"outputs">> := List} = Map
>
> and if you know that it's always going to be the second entry in the
> list, you can pattern-match that with this:
>
>     [_, Element | _] = List
>
>     Note that with the map pattern, the key must always be either a
> literal or a bound variable. Also note the required use of :=, which
> is the "mandatory key" syntax, as opposed to =>, which is "optional
> key". You can match multiple key/value pairs in a map in a single
> pattern.
>
>> my_binary_to_list(<<H,T/binary>>) ->
>>      [H|my_binary_to_list(T)];
>> my_binary_to_list(<<>>) -> [].
>     Why not just use binary_to_list/1 in the erlang module?
>
>     Hugo.
>
>> prints:
>>
>> "MME", "Speakers (Realtek High Definiti"
>>
>> Thanks in advance, Bob
>> _______________________________________________
>> erlang-questions mailing list
>> [hidden email]
>> http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Maps and binaries

Hugo Mills-2
On Wed, Dec 12, 2018 at 02:58:54PM +0000, Bob Cowdery wrote:

> Hi Hugo
>
> Thanks, all good points. This is test code just sorting out how to
> do things. I have a problem with encoding now.
>
> This is my map:
>
> msg(set_audio_route) -> #{<<"cmd">> => <<"set_audio_route">>,
> <<"params">> => []};
>
> to which I add parameters and encode.
> PMsg = maps:put(<<"params">>, [1, "LOCAL", 1, Api, Dev, "BOTH"],
> msg(set_audio_route)),
> FullMsg = jsone:encode(PMsg),
>
> This encodes to:
>
> SetRoute - <<"{\"cmd\":\"set_audio_route\",\"params\":[1,[76,79,67,65,76],1,[77,77,69],[83,112,101,97,107,101,114,115,32,40,82,101,97,108,116,101,107,32,72,105,103,104,32,68,101,102,105,110,105,116,105],[66,79,84,72]]}">>
   I don't know the jsone library, but it looks like it's encoding
binaries to strings, and lists to lists (whether the lists are
intended to be strings or not). This kind of makes sense, given the
way erlang represents strings, in that it gives the encoder a concrete
statement of what to encode as a string and what as a list.

   Does it do the right thing if you write <<"LOCAL">> and <<"BOTH">>,
and you don't convert Api and Dev to a list?

   Hugo.

> The problem is my C lib when I decode the Json is expecting strings
> in the list and it gets lists. I'm doing this in a few languages at
> the moment so can't change the C for one language when its working
> for others. Is there a way around this?
>
> Bob)
>
> On 12/12/2018 10:37, Hugo Mills wrote:
> >    Hi, Bob,
> >
> >On Wed, Dec 12, 2018 at 10:24:35AM +0000, Bob Cowdery wrote:
> >>Its a long time since using Erlang so just getting back in. I know
> >>that there is always better ways to do things so is there a better
> >>patten matching way than this straight forward step-wise method.
> >>I have output from a UDP request put through jstone:decode which
> >>ends up like so:
> >>#{<<"outputs">> =>
> >>       [#{<<"api">> => <<"MME">>,<<"channels">> => 2,<<"direction">> => 1,
> >>          <<"index">> => 5,<<"name">> => <<"Microsoft Sound Mapper -
> >>Output">>},
> >>        #{<<"api">> => <<"MME">>,<<"channels">> => 8,<<"direction">> => 1,
> >>          <<"index">> => 6,<<"name">> => <<"Speakers (Realtek High
> >>Definiti">>},
> >>...
> >>      #{<<"api">> => <<>>,<<"channels">> => 0,<<"direction">> => 0,
> >>          <<"index">> => 0,<<"name">> => <<>>}]}
> >>I want to extract the second member api and name.
> >>
> >>     Map = jsone:decode(Resp),
> >>     List = maps:get(<<"outputs">>, Map),
> >>     Element = lists:nth(2, List),
> >>     Api = my_binary_to_list(maps:get(<<"api">>, Element)),
> >>     Dev = my_binary_to_list(maps:get(<<"name">>, Element)),
> >>     io:format("~p, ~p~n", [Api, Dev]).
> >    This seems perfectly reasonable as it is. However, you can
> >pattern-match maps this way:
> >
> >    #{<<"outputs">> := List} = Map
> >
> >and if you know that it's always going to be the second entry in the
> >list, you can pattern-match that with this:
> >
> >    [_, Element | _] = List
> >
> >    Note that with the map pattern, the key must always be either a
> >literal or a bound variable. Also note the required use of :=, which
> >is the "mandatory key" syntax, as opposed to =>, which is "optional
> >key". You can match multiple key/value pairs in a map in a single
> >pattern.
> >
> >>my_binary_to_list(<<H,T/binary>>) ->
> >>     [H|my_binary_to_list(T)];
> >>my_binary_to_list(<<>>) -> [].
> >    Why not just use binary_to_list/1 in the erlang module?
> >
> >    Hugo.
> >
> >>prints:
> >>
> >>"MME", "Speakers (Realtek High Definiti"
> >>
> >>Thanks in advance, Bob
> >>_______________________________________________
> >>erlang-questions mailing list
> >>[hidden email]
> >>http://erlang.org/mailman/listinfo/erlang-questions
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions
--
Hugo Mills             | Every time you make a typo, the errorists win.
hugo@... carfax.org.uk |
http://carfax.org.uk/  |
PGP: E2AB1DE4          |

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

signature.asc (853 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Maps and binaries

Bob Cowdery-4
Yes it does, thank you. I tried a few things around that theme but
didn't do it quite right.

On 12/12/2018 15:06, Hugo Mills wrote:

> On Wed, Dec 12, 2018 at 02:58:54PM +0000, Bob Cowdery wrote:
>> Hi Hugo
>>
>> Thanks, all good points. This is test code just sorting out how to
>> do things. I have a problem with encoding now.
>>
>> This is my map:
>>
>> msg(set_audio_route) -> #{<<"cmd">> => <<"set_audio_route">>,
>> <<"params">> => []};
>>
>> to which I add parameters and encode.
>> PMsg = maps:put(<<"params">>, [1, "LOCAL", 1, Api, Dev, "BOTH"],
>> msg(set_audio_route)),
>> FullMsg = jsone:encode(PMsg),
>>
>> This encodes to:
>>
>> SetRoute - <<"{\"cmd\":\"set_audio_route\",\"params\":[1,[76,79,67,65,76],1,[77,77,69],[83,112,101,97,107,101,114,115,32,40,82,101,97,108,116,101,107,32,72,105,103,104,32,68,101,102,105,110,105,116,105],[66,79,84,72]]}">>
>     I don't know the jsone library, but it looks like it's encoding
> binaries to strings, and lists to lists (whether the lists are
> intended to be strings or not). This kind of makes sense, given the
> way erlang represents strings, in that it gives the encoder a concrete
> statement of what to encode as a string and what as a list.
>
>     Does it do the right thing if you write <<"LOCAL">> and <<"BOTH">>,
> and you don't convert Api and Dev to a list?
>
>     Hugo.
>
>> The problem is my C lib when I decode the Json is expecting strings
>> in the list and it gets lists. I'm doing this in a few languages at
>> the moment so can't change the C for one language when its working
>> for others. Is there a way around this?
>>
>> Bob)
>>
>> On 12/12/2018 10:37, Hugo Mills wrote:
>>>     Hi, Bob,
>>>
>>> On Wed, Dec 12, 2018 at 10:24:35AM +0000, Bob Cowdery wrote:
>>>> Its a long time since using Erlang so just getting back in. I know
>>>> that there is always better ways to do things so is there a better
>>>> patten matching way than this straight forward step-wise method.
>>>> I have output from a UDP request put through jstone:decode which
>>>> ends up like so:
>>>> #{<<"outputs">> =>
>>>>        [#{<<"api">> => <<"MME">>,<<"channels">> => 2,<<"direction">> => 1,
>>>>           <<"index">> => 5,<<"name">> => <<"Microsoft Sound Mapper -
>>>> Output">>},
>>>>         #{<<"api">> => <<"MME">>,<<"channels">> => 8,<<"direction">> => 1,
>>>>           <<"index">> => 6,<<"name">> => <<"Speakers (Realtek High
>>>> Definiti">>},
>>>> ...
>>>>       #{<<"api">> => <<>>,<<"channels">> => 0,<<"direction">> => 0,
>>>>           <<"index">> => 0,<<"name">> => <<>>}]}
>>>> I want to extract the second member api and name.
>>>>
>>>>      Map = jsone:decode(Resp),
>>>>      List = maps:get(<<"outputs">>, Map),
>>>>      Element = lists:nth(2, List),
>>>>      Api = my_binary_to_list(maps:get(<<"api">>, Element)),
>>>>      Dev = my_binary_to_list(maps:get(<<"name">>, Element)),
>>>>      io:format("~p, ~p~n", [Api, Dev]).
>>>     This seems perfectly reasonable as it is. However, you can
>>> pattern-match maps this way:
>>>
>>>     #{<<"outputs">> := List} = Map
>>>
>>> and if you know that it's always going to be the second entry in the
>>> list, you can pattern-match that with this:
>>>
>>>     [_, Element | _] = List
>>>
>>>     Note that with the map pattern, the key must always be either a
>>> literal or a bound variable. Also note the required use of :=, which
>>> is the "mandatory key" syntax, as opposed to =>, which is "optional
>>> key". You can match multiple key/value pairs in a map in a single
>>> pattern.
>>>
>>>> my_binary_to_list(<<H,T/binary>>) ->
>>>>      [H|my_binary_to_list(T)];
>>>> my_binary_to_list(<<>>) -> [].
>>>     Why not just use binary_to_list/1 in the erlang module?
>>>
>>>     Hugo.
>>>
>>>> prints:
>>>>
>>>> "MME", "Speakers (Realtek High Definiti"
>>>>
>>>> Thanks in advance, Bob
>>>> _______________________________________________
>>>> erlang-questions mailing list
>>>> [hidden email]
>>>> http://erlang.org/mailman/listinfo/erlang-questions
>> _______________________________________________
>> erlang-questions mailing list
>> [hidden email]
>> http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions