{"id":6095,"date":"2012-08-10T17:42:38","date_gmt":"2012-08-10T12:12:38","guid":{"rendered":"http:\/\/www.tothenew.com\/blog\/?p=6095"},"modified":"2016-11-29T17:30:35","modified_gmt":"2016-11-29T12:00:35","slug":"groovier-way-of-sorting-over-multiple-fields-in-a-list-of-maps-in-groovy","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/groovier-way-of-sorting-over-multiple-fields-in-a-list-of-maps-in-groovy\/","title":{"rendered":"Groovier way of sorting over multiple fields in a list of maps in groovy"},"content":{"rendered":"<p>Recently I was working on a <a title=\"Grails Development\" href=\"http:\/\/www.tothenew.com\/grails-application-development\" target=\"_blank\">Groovy and Grails Development<\/a> project and had a requirement to sort multiple fields in a list of maps.<\/p>\n<p>I needed to sort the below list of maps by firstName, then by lastName and then by ascending age. It means first, the firstNames will be compared. If they are same, lastNames will be compared and even if they are same, ages will be compared to decide order.<\/p>\n<p>[java]<br \/>\nList list = [<br \/>\n    [id:0, firstName: &#8216;Sachin&#8217;, lastName: &#8216;Tendulkar&#8217;, age: 40 ],<br \/>\n    [id:1, firstName: &#8216;Sachin&#8217;, lastName: &#8216;Tendulkar&#8217;, age: 103 ],<br \/>\n    [id:2, firstName: &#8216;Ajay&#8217;, lastName: &#8216;Tendulkar&#8217;, age: 48 ],<br \/>\n    [id:3, firstName: &#8216;Virendra&#8217;, lastName: &#8216;Sehwag&#8217;, age: 5 ],<br \/>\n    [id:4, firstName: &#8216;Virendra&#8217;, lastName: &#8216;Sehwag&#8217;, age: 50 ],<br \/>\n    [id:5, firstName: &#8216;Sachin&#8217;, lastName: &#8216;Nayyar&#8217;, age: 15 ]<br \/>\n]<br \/>\n[\/java]<\/p>\n<p>One way to achieve this is to use spaceship operator as follows :<\/p>\n<p>[java]<br \/>\nlist.sort { a,b -&gt;<br \/>\n   a.firstName &lt;=&gt; b.firstName ?: a.lastName &lt;=&gt; b.lastName ?: a.age &lt;=&gt; b.age<br \/>\n}*.id<br \/>\n[\/java]<\/p>\n<p>which gives the correct output as a list of id&#8217;s = [2, 5, 0, 1, 3, 4]<\/p>\n<p>One <a title=\"groovy developer\" href=\"http:\/\/www.tothenew.com\/grails-application-development\">cool groovier way<\/a> of achieving the same result is to concatenate firstName,lastName and age fields as a single string and then use the resulted string in sorting. However, there will be a problem with sorting age in this manner. Among two ages, 40 and 103, groovy will treat 103 as lower than 40, because sorting is done in ASCII\u00a0collating sequence and in that 1 of 103 comes before 4 of 40.<\/p>\n<p>One way to rectify this problem is to left-pad the age with sufficient number of 0&#8217;s before it is compared. Thus, 40 will become 040 and 103 will remain as it is and we will get the correct ordering. (Special thanks to my colleague\u00a0<a href=\"http:\/\/www.tothenew.com\/blog\/author\/bhagwat\/\">Bhagwat<\/a>\u00a0for helping me to arrive at this solution)<\/p>\n<p>[java]<br \/>\nString padAge(Integer age){<br \/>\n    return String.format(&quot;%03d&quot;,age)<br \/>\n}<br \/>\n[\/java]<\/p>\n<p>In format &#8220;%03d&#8221;, 0 specifies the filler digit and 3 specifies the maximum number of digits after padding. Thus, our final one-liner to perform sorting over multiple fields becomes :<\/p>\n<p>[java]<br \/>\nlist.sort{it.firstName+it.lastName+padAge(it.age)}*.id<br \/>\n[\/java]<\/p>\n<p>and output will be [2, 5, 0, 1, 3, 4]<\/p>\n<p>I\u00a0Hope it will be helpful.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently I was working on a Groovy and Grails Development project and had a requirement to sort multiple fields in a list of maps. I needed to sort the below list of maps by firstName, then by lastName and then by ascending age. It means first, the firstNames will be compared. If they are same, [&hellip;]<\/p>\n","protected":false},"author":46,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":261},"categories":[7],"tags":[859,858,505],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/6095"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/46"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=6095"}],"version-history":[{"count":0,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/6095\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=6095"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=6095"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=6095"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}