Kaps
Kaps

Reputation: 23

Veocity : How to find frequency of values in array and then sort the values in the order of frequency

I have any array in velocity which has duplicate values too. I want to create an array with unique values where all the values are sorted based on their count/frequency in the original array.

For example:

                #set($y = 0)
                #set ($pagelist = [])
                #foreach($label in $page.labels) 
                    #set($pinnedPages = $repository.getContentByLabel("$!label"))
                    #set($currentpage = $page)
                 
                    ## Display the page that has a label that matches current page label.            
                    #foreach($page in $pinnedPages)
                        #if($page != $currentpage)
                            ## Display the page name as a list item. 
                            #set ($pagelistswallow = $pagelist.add($page.title))
                            <li>$pagelist.get($y)</li>
                            #set($y = $y + 1)
                        #end
                    #end            
                #end

The pagelist array has page names and few of them occur multiple times in this array . I need an array with unique page names sorted in the order of their frequency in the original pagelist array.

Can anyone help? I have tried but my code is not working...

Upvotes: 0

Views: 355

Answers (1)

Claude Brisson
Claude Brisson

Reputation: 4130

You can do :

#foreach($label in $page.labels) 
  #set($pinnedPages = $repository.getContentByLabel("$!label"))
  #set($currentpage = $page)
  
  ## Prepare a map (title -> occurrences) of pages
  ## which have a label that matches current page label.
  
  #set($pagemap = {})
  #foreach($subpage in $pinnedPages)
    #if($subpage != $page)
      #set($junk = $pagemap.put(
        $page.title,
        $pagemap.getOrDefault($page.title, 0) + 1))
    #end
  #end

  ## Calculate a map (occ, title) -> title

  #set($pagetmp = {})
  #foreach($entry in $pagemap.entrySet())
    #set($junk = $pagetmp.put(
      "${entry.value}_${entry.key}",
      $entry.key))
  #end

  ## Display those related pages by increasing
  ## number of occurrences (just reverse the array
  ## for a decreasing order)

  #set($pagekeys = $pagetmp.keySet().stream().sorted().toArray())
  #foreach($key in $pagekeys)
    <li>(label: $label) $pagetmp.get($key)</li>
  #end

#end

The need to use sorted() explicitely comes from the fact that Velocity empty maps are LinkedHashMap, hence keys order is a hash, not the natural order.

As a variant, to be able to display the number of occurrences, you can easily adapt this code to have $pagetmp values be a map { occ, title }.

Edit

If you're using Velocity 1.6, you have to split the instruction #set($junk = ...) into :

#set($subinit = $pagemap.getOrDefault($pagetitle, 0) + 1)
#set($junk = $pagemap.put($page.title, $ubinit))

Upvotes: 1

Related Questions