<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Chewing the Cud (Posts about erlang kazoo 2600Hz)</title><link>https://jamesaimonetti.com/</link><description></description><atom:link href="https://jamesaimonetti.com/categories/erlang-kazoo-2600hz.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><lastBuildDate>Fri, 28 Mar 2025 22:42:18 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Using Erlang's =maps:groups_from_list/2= function</title><link>https://jamesaimonetti.com/posts/using-erlangs-mapsgroups_from_list2-function/</link><dc:creator>James Aimonetti</dc:creator><description>&lt;p&gt;
Since OTP 25, Erlang has included a function &lt;code&gt;maps:groups_from_list/2&lt;/code&gt; and I had occasion to use it recently.
&lt;/p&gt;

&lt;p&gt;
In &lt;a href="https://github.com/2600hz/kazoo"&gt;KAZOO&lt;/a&gt;, we have a process that monitors other processes, keeping track of their message queue length, heap size, etc (we're on OTP 26 at the moment so need to do this manually).
&lt;/p&gt;

&lt;p&gt;
I wanted to print a table of the tracked processes, ordered first by message queue length, but within the group, sorted by heap size.
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="ni"&gt;record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;proc_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message_queue_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total_heap_size&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;

&lt;span class="nf"&gt;sort_processes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Processes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c"&gt;%% Groups = #{mql =&amp;gt; [#proc_info{}...]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;Grouped&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;groups_from_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;#proc_info&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;message_queue_len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;MQL&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;MQL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="w"&gt;				   &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;Processes&lt;/span&gt;
&lt;span class="w"&gt;				   &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nn"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;fold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fun&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sort_group_by_heap&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Grouped&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;

&lt;span class="nf"&gt;sort_group_by_heap&lt;/span&gt;&lt;span class="p"&gt;(_&lt;/span&gt;&lt;span class="nv"&gt;MQL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ProcInfos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nn"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;keysort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;#proc_info.total_heap_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ProcInfos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Acc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;
The first argument is used to extract the each list element a "key" to use when inserting the element into the resulting map. In my case, the grouping was for &lt;code&gt;message_queue_len&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
The &lt;code&gt;Grouped&lt;/code&gt; map() will contain keys corresponding to the unique set of message queue lengths, and the value will be the list of &lt;code&gt;#proc_info{}&lt;/code&gt; records.
&lt;/p&gt;

&lt;p&gt;
There is an arity-3 version where you can map the list element into a new value to be put into the grouping's list of results as well. As I want to sort the records by &lt;code&gt;total_heap_size&lt;/code&gt; after grouping, I had no cause to use it.
&lt;/p&gt;

&lt;div id="outline-container-org91a2faa" class="outline-2"&gt;
&lt;h2 id="org91a2faa"&gt;What I like about Erlang records&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-org91a2faa"&gt;
&lt;p&gt;
Records get a bad rap in Erlang, especially now that maps exist. I find the utility of records to be so great that I reach for them way more often than for maps when I have a fixed amount of fields. Records work really well with the &lt;code&gt;lists:key*&lt;/code&gt; functions to, providing the index into the record tuple as above in &lt;code&gt;sort_group_by_heap&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
One day I'll write more about how I use records but wanted to mention this specific use as a common one in my work.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description><category>erlang kazoo 2600Hz</category><guid>https://jamesaimonetti.com/posts/using-erlangs-mapsgroups_from_list2-function/</guid><pubDate>Fri, 28 Mar 2025 22:28:07 GMT</pubDate></item></channel></rss>