oym
oym

Reputation: 7083

Scala writing a chunked iterator

I am using Scala and the Play Framework. Given an Iterable of Widgets I can easily loop through them and print them as follows (using the @ because this is within a Play template, but that can be ignored for the sake of the question):

@for(widget <- widgets) {
  <div>My widget: @widget</div>  
}

Now suppose I have a column layout where I need to show 3 widgets per row. Say I'd want output html as follows:

<div class="row">
  <div>widget</div>
  <div>widget</div>
  <div>widget</div>
</div>
<div class="row">
  <div>widget</div>
  <div>widget</div>
  <div>widget</div>
</div>
<div class="row">
  <div>widget</div>      
</div>

I am trying to write a "chunked" iterator to achieve this so that the mod checks (or however its implemented) can be internalized. So in other words, I think it would be nice if I could write:

@chunk(3) {
  <div class="row"> <!-- gets printed once per chunk --> 

    @for(widget <- widgets) { // gets called for each widget in widgets
      <div>@widget</div>  
    }

  </div> <!-- gets printed once per chunk -->  
}

But this is not a correct way that something like this could be invoked: the chunk call needs to have the context of Widgets so that the "inner" iteration can be invoked properly (once per each chunk). I am not sure what the best way to proceed with the implementation in Scala is.

The alternative of course is just to write a loop with an index and do a mod check. But don't think that would be as clean of a solution. I couldn't find anything like this built into Play's templating engine. Freemarker, for instance, does provide a chunked operation.

Upvotes: 1

Views: 190

Answers (1)

Michael Zajac
Michael Zajac

Reputation: 55569

The Scala collections API has your back with grouped.

Say you have widgets: List[Widget] in scope.

@for(group <- widgets.grouped(3)) {
    <div class="row">
    @for(widget <- group) {
        <div>@widget</div>  
    }
    </div>
}

grouped(3) will return at Iterator[List[Widget]], where each List[Widget] a size of at most 3--doing exactly what you describe.

Illustrated with Ints:

scala> List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).grouped(3).foreach(println _)

List(1, 2, 3)
List(4, 5, 5)
List(6, 7, 8)
List(9, 10)

Upvotes: 2

Related Questions