Counting pattern in scala list - scala

My list looks like the following: List(Person,Invite,Invite,Person,Invite,Person...). I am trying to match based on a inviteCountRequired, meaning that the Invite objects following the Person object in the list is variable. What is the best way of doing this? My match code so far looks like this:
aList match {
case List(Person(_,_,_),Invitee(_,_,_),_*) => ...
case _ => ...
}
First stack question, please go easy on me.

Let
val aList = List(Person(1), Invite(2), Invite(3), Person(2), Invite(4), Person(3), Invite(6), Invite(7))
Then index each location in the list and select Person instances,
val persons = (aList zip Stream.from(0)).filter {_._1.isInstanceOf[Person]}
namely, List((Person(1),0), (Person(2),3), (Person(3),5)) . Define then sublists where the lower bound corresponds to a Person instance,
val intervals = persons.map{_._2}.sliding(2,1).toArray
res31: Array[List[Int]] = Array(List(0, 3), List(3, 5))
Construct sublists,
val latest = aList.drop(intervals.last.last) // last Person and Invitees not paired
val associations = intervals.map { case List(pa,pb,_*) => b.slice(pa,pb) } ++ latest
Hence the result looks like
Array(List(Person(1), Invite(2), Invite(3)), List(Person(2), Invite(4)), List(Person(3), Invite(6), Invite(7)))
Now,
associations.map { a =>
val person = a.take(1)
val invitees = a.drop(1)
// ...
}
This approach may be seen as a variable size sliding.

Thanks for your tips. I ended up creating another case class:
case class BallotInvites(person:Person,invites:List[Any])
Then, I populated it from the original list:
def constructBallotList(ballots:List[Any]):List[BallotInvites] ={
ballots.zipWithIndex.collect {
case (iv:Ballot,i) =>{
BallotInvites(iv,
ballots.distinct.takeRight(ballots.distinct.length-(i+1)).takeWhile({
case y:Invitee => true
case y:Person =>true
case y:Ballot => false})
)}
}}
val l = Ballot.constructBallotList(ballots)
Then to count based on inviteCountRequired, I did the following:
val count = l.count(b=>if ((b.invites.count(x => x.isInstanceOf[Person]) / contest.inviteCountRequired)>0) true else false )

I am not sure I understand the domain but you should only need to iterate once to construct a list of person + invites tuple.
sealed trait PorI
case class P(i: Int) extends PorI
case class I(i: Int) extends PorI
val l: List[PorI] = List(P(1), I(1), I(1), P(2), I(2), P(3), P(4), I(4))
val res = l.foldLeft(List.empty[(P, List[I])])({ case (res, t) =>
t match {
case p # P(_) => (p, List.empty[I]) :: res
case i # I(_) => {
val head :: tail = res
(head._1, i :: head._2) :: tail
}
}
})
res // List((P(4),List(I(4))), (P(3),List()), (P(2),List(I(2))), (P(1),List(I(1), I(1))))

Related

Find person and immediate neighbours in Seq[Person]

Given a Seq[Person], which contains 1-n Persons (and the minimum 1 Person beeing "Tom"), what is the easiest approach to find a Person with name "Tom" as well as the Person right before Tome and the Person right after Tom?
More detailed explanation:
case class Person(name:String)
The list of persons can be arbitrarily long, but will have at least one entry, which must be "Tom". So those lists can be a valid case:
val caseOne = Seq(Person("Tom"), Person("Mike"), Person("Dude"),Person("Frank"))
val caseTwo = Seq(Person("Mike"), Person("Tom"), Person("Dude"),Person("Frank"))
val caseThree = Seq(Person("Tom"))
val caseFour = Seq(Person("Mike"), Person("Tom"))
You get the idea. Since I already have "Tom", the task is to get his left neighbour (if it exists), and the right neighbour (if it exists).
What is the most efficient way to achieve to do this in scala?
My current approach:
var result:Tuple2[Option[Person], Option[Person]] = (None,None)
for (i <- persons.indices)
{
persons(i).name match
{
case "Tom" if i > 0 && i < persons.size-1 => result = (Some(persons(i-1)), Some(persons(i+1))) // (...), left, `Tom`, right, (...)
case "Tom" if i > 0 => result = (Some(persons(i-1)), None) // (...), left, `Tom`
case "Tom" if i < persons.size-1 => result = (Some(persons(i-1)), None) // `Tom`, right, (...)
case "Tom" => result = (None, None) // `Tom`
}
}
Just doesn't feel like I am doing it the scala way.
Solution by Mukesh prajapati:
val arrayPersons = persons.toArray
val index = arrayPersons.indexOf(Person("Tom"))
if (index >= 0)
result = (arrayPersons.lift(index-1), arrayPersons.lift(index+1))
Pretty short, seems to cover all cases.
Solution by anuj saxena
result = persons.sliding(3).foldLeft((Option.empty[Person], Option.empty[Person]))
{
case ((Some(prev), Some(next)), _) => (Some(prev), Some(next))
case (_, prev :: Person(`name`) :: next :: _) => (Some(prev), Some(next))
case (_, _ :: prev :: Person(`name`) :: _) => (Some(prev), None)
case (_, Person(`name`) :: next :: _) => (None, Some(next))
case (neighbours, _) => neighbours
}
First find out index where "Tom" is present, then use "lift". "lift" turns partial function into a plain function returning an Option result:
index = persons.indexOf("Tom")
doSomethingWith(persons.lift(index-1), persons.lift(index+1))
A rule of thumb: we should never access the content of a list / seq using indexes as it is prone to errors (like IndexNotFoundException).
If we want to use indexes, we better use Array as it provides us random access.
So to the current solution, here is my code to find prev and next element of a certain data in a Seq or List:
def findNeighbours(name: String, persons: Seq[Person]): Option[(Person, Person)] = {
persons.sliding(3).flatMap{
case prev :: person :: next :: Nil if person.name == name => Some(prev, next)
case _ => None
}.toList.headOption
}
Here the return type is in Option because there is a possibility that we may not find it here (in case of only one person is in the list or the required person is not in the list).
This code will pick the pair on the first occurrence of the person provided in the parameter.
If you have a probability that there might be several occurrences for the provided person, remove the headOption in the last line of the function findNeighbours. Then it will return a List of tuples.
Update
If Person is a case class then we can use deep match like this:
def findNeighbours(name: String, persons: Seq[Person]): Option[(Person, Person)] = {
persons.sliding(3).flatMap{
case prev :: Person(`name`) :: next :: Nil => Some(prev, next)
case _ => None
}.toList.headOption
}
For your solution need to add more cases to it (cchanged it to use foldleft in case of a single answer):
def findNeighboursV2(name: String, persons: Seq[Person]): (Option[Person], Option[Person]) = {
persons.sliding(3).foldLeft((Option.empty[Person], Option.empty[Person])){
case ((Some(prev), Some(next)), _) => (Some(prev), Some(next))
case (_, prev :: Person(`name`) :: next :: _) => (Some(prev), Some(next))
case (_, _ :: prev :: Person(`name`) :: _) => (Some(prev), None)
case (_, Person(`name`) :: next :: _) => (None, Some(next))
case (neighbours, _) => neighbours
}
}
You can use sliding function:
persons: Seq[Person] = initializePersons()
persons.sliding(size = 3).find { itr =>
if (itr(1).name = "Tom") {
val before = itr(0)
val middle = itr(1)
val after = itr(2)
}
}
If you know that there will be only one instance of "Tom" in your Seq use indexOf instead of looping by hand:
tomIndex = persons.indexOf("Tom")
doSomethingWith(persons(tomIndex-1), persons(tomIndex+1))
// Start writing your ScalaFiddle code here
case class Person(name: String)
val persons1 = Seq(Person("Martin"),Person("John"),Person("Tom"),Person("Jack"),Person("Mary"))
val persons2 = Seq(Person("Martin"),Person("John"),Person("Tom"))
val persons3 = Seq(Person("Tom"),Person("Jack"),Person("Mary"))
val persons4 = Seq(Person("Tom"))
def f(persons:Seq[Person]) =
persons
.sliding(3)
.filter(_.contains(Person("Tom")))
.maxBy {
case _ :: Person("Tom") :: _ => 1
case _ => 0
}
.toList
.take(persons.indexOf(Person("Tom")) + 2) // In the case where "Tom" is first, drop the last person
.drop(persons.indexOf(Person("Tom")) - 1) // In the case where "Tom" is last, drop the first person
println(f(persons1)) // List(Person(John), Person(Tom), Person(Jack))
println(f(persons2)) // List(Person(John), Person(Tom))
println(f(persons3)) // List(Person(Tom), Person(Jack))
println(f(persons4)) // List(Person(Tom))
Scalafiddle

list with case class scala

I have the following issue I have the following list as input
val input:List[Item]=List(FRDVE,12
SDED,13
prog-d,11
PROG-D,15
a-prog-d,17)
with
case class Item(Name:String,Number:Int)
The aim is to find only first line where name contains either prog-d or PROG-D
so for this case the expected output is:
val output="prog-d"
I wrote the following code :
def getName(input:List[Item]):Option[String]={
val matchLine=input.filter(Name.contains("prog-d"))
matchLine match {
case head::tail => Some(matchLine.head.split(",")(0))
case isEmpty => None
}
}
so here I am getting an error saying that the Name doesn't exist and I don't know how to put different possibilities in the contains : here it should basically be : Name.contains("prog-d" ||"PROG-D")
Any recommendations please
Thanks a lot
You can use collectFirst:
input.collectFirst { case Item(s, _) if s.equalsIgnoreCase("prog-d") => s }
This avoids both map and filter, so that only the minimal necessary amount of entries is inspected.
Full code:
case class Item(name: String, number: Int)
val input: List[Item] = List(
Item("FRDVE", 12),
Item("SDED", 13),
Item("prog-d", 11),
Item("PROG-D", 15),
Item("a-prog-d", 17),
)
val output = input.collectFirst {
case Item(s, _) if s.equalsIgnoreCase("prog-d") => s
}
println(output)
You can also use find where this function returns the option of first elements whichever matches your condition (stops iterating on remaining elements).
case class Item(Name:String,Number:Int)
val input = List(Item("FRDVE",12), Item("SDED",13), Item("prog-d",11), Item("PROG-D",15), Item("a-prog-d",17))
input.find(_.Name.equalsIgnoreCase("prog-d")) match {
case Some(item) => item.Name
case None => "" //your default string
}
you can use item.Name == "prog-d" || item.Name == "PROG-D" or item.Name.equalsIgnoreCase("prog-d")
scala> val input = List(Item("FRDVE",12), Item("SDED",13), Item("prog-d",11), Item("PROG-D",15), Item("a-prog-d",17))
input: List[Item] = List(Item(FRDVE,12), Item(SDED,13), Item(prog-d,11), Item(PROG-D,15), Item(a-prog-d,17))
scala> input.filter(item => item.Name.equalsIgnoreCase("prog-d")).map(_.Name)
res1: List[String] = List(prog-d, PROG-D)
If you want the first match, do headOption and play with it based on what data you want.
scala> val output = input.filter(item => item.Name.equalsIgnoreCase("prog-d")).headOption
output: Option[Item] = Some(Item(prog-d,11))
scala> val outputName = input.filter(item => item.Name.equalsIgnoreCase("prog-d")).headOption.map(_.Name)
outputName: Option[String] = Some(prog-d)
NOTE: (.head is not safe to use because List().head will explode when list is empty)
scala> List.empty[Item].head
java.util.NoSuchElementException: head of empty list
at scala.collection.immutable.Nil$.head(List.scala:428)
at scala.collection.immutable.Nil$.head(List.scala:425)
... 28 elided

Build conditionally list avoiding mutations

Let's say I want to build list of Pizza's ingredients conditionally:
val ingredients = scala.collection.mutable.ArrayBuffer("tomatoes", "cheese")
if (!isVegetarian()) {
ingredients += "Pepperoni"
}
if (shouldBeSpicy()) {
ingredients += "Jalapeno"
}
//etc
Is there functional way to build this array using immutable collections?
I thought about:
val ingredients = List("tomatoes", "cheese") ++ List(
if (!isVegetarian()) Some("Pepperoni") else None,
if (shouldBeSpicy()) Some("Jalapeno") else None
).flatten
but is there better way?
Here is another possible way that is closer to #Antot but IMHO is much simpler.
What is unclear in your original code is where isVegetarian and shouldBeSpicy actually come from. Here I assume that there is a PizzaConf class as following to provide those configuration settings
case class PizzaConf(isVegetarian: Boolean, shouldBeSpicy: Boolean)
Assuming this, I think the simplest way is to have a allIngredients of List[(String, Function1[PizzaConf, Boolean])] type i.e. one that stores ingredients and functions to check their corresponding availability. Given that buildIngredients becomes trivial:
val allIngredients: List[(String, Function1[PizzaConf, Boolean])] = List(
("Pepperoni", conf => conf.isVegetarian),
("Jalapeno", conf => conf.shouldBeSpicy)
)
def buildIngredients(pizzaConf: PizzaConf): List[String] = {
allIngredients
.filter(_._2(pizzaConf))
.map(_._1)
}
or you can merge filter and map using collect as in following:
def buildIngredients(pizzaConf: PizzaConf): List[String] =
allIngredients.collect({ case (ing, cond) if cond(pizzaConf) => ing })
Your original approach is not bad. I would probably just stick with list:
val ingredients =
List("tomatoes", "cheese") ++
List("Pepperoni", "Sausage").filter(_ => !isVegetarian) ++
List("Jalapeno").filter(_ => shouldBeSpicy)
Which makes it easy to add more ingredients connected to a condition (see "Sausage" above)
You could start with the full list of ingredients and then filter out the ingredients not passing the conditions:
Set("tomatoes", "cheese", "Pepperoni", "Jalapeno")
.filter {
case "Pepperoni" => !isVegetarian;
case "Jalapeno" => shouldBeSpicy;
case _ => true // ingredients by default
}
which for:
val isVegetarian = true
val shouldBeSpicy = true
would return:
Set(tomatoes, cheese, Jalapeno)
This can be achieved by creating a sequence of predicates, which defines the conditions applied to filter the ingredients.
// available ingredients
val ingredients = Seq("tomatoes", "cheese", "ham", "mushrooms", "pepper", "salt")
// predicates
def isVegetarian(ingredient: String): Boolean = ingredient != "ham"
def isSpicy(ingredient: String): Boolean = ingredient == "pepper"
def isSalty(ingredient: String): Boolean = ingredient == "salt"
// to negate another predicate
def not(predicate: (String) => Boolean)(ingr: String): Boolean = !predicate(ingr)
// sequences of conditions for different pizzas:
val vegeterianSpicyPizza: Seq[(String) => Boolean] = Seq(isSpicy, isVegetarian)
val carnivoreSaltyNoSpices: Seq[(String) => Boolean] = Seq(not(isSpicy), isSalty)
// main function: builds a list of ingredients for specified conditions!
def buildIngredients(recipe: Seq[(String) => Boolean]): Seq[String] = {
ingredients.filter(ingredient => recipe.exists(_(ingredient)))
}
println("veg spicy: " + buildIngredients(vegeterianSpicyPizza))
// veg spicy: List(tomatoes, cheese, mushrooms, pepper, salt)
println("carn salty: " + buildIngredients(carnivoreSaltyNoSpices))
// carn salty: List(tomatoes, cheese, ham, mushrooms, salt)
Inspired by other answers, I came up with something like this:
case class If[T](conditions: (Boolean, T)*) {
def andAlways(values: T*): List[T] =
conditions.filter(_._1).map(_._2).toList ++ values
}
It could be used like:
val isVegetarian = false
val shouldBeSpicy = true
val ingredients = If(
!isVegetarian -> "Pepperoni",
shouldBeSpicy -> "Jalapeno",
).andAlways(
"Cheese",
"Tomatoes"
)
Still waiting for a better option :)
If any ingredient will only need testing against one condition, you could do something like this:
val commonIngredients = List("Cheese", "Tomatoes")
val nonVegetarianIngredientsWanted = {
if (!isVegetarian)
List("Pepperoni")
else
List.empty
}
val spicyIngredientsWanted = {
if (shouldBeSpicy)
List("Jalapeno")
else
List.empty
}
val pizzaIngredients = commonIngredients ++ nonVegetarianIngredientsWanted ++ spicyIngredientsWanted
This doesn't work if you have ingredients which are tested in two categories: for example if you have spicy sausage then that should only be included if !isVegetarian and spicyIngredientsWanted. One method of doing this would be to test both conditions together:
val (optionalIngredients) = {
(nonVegetarianIngredientsWanted, spicyIngredientsWanted) match {
case (false, false) => List.empty
case (false, true) => List("Jalapeno")
case (true, false) => List("Pepperoni")
case (true, true) => List("Pepperoni, Jalapeno, Spicy Sausage")
}
val pizzaIngredients = commonIngredients ++ optionalIngredients
This can be extended to test any number of conditions, though of course the number of case arms needed extends exponentially with the number of conditions tested.

Filter collection regarding to some state

Sorry for blurry description, but I can't describe better. So, the problem -
I have hierarchy of classes
sealed trait GameEvent
case object RoundStarted extends GameEvent
case object MessageSent extends GameEvent
....
After parsing game data, I have List[GameEvent]. By business logic, I need provide ability to "view" game at particular round. Start of each round determined by RoundStartedEvent. API method have following signature:
def load(id:Int, round:Int) = {
val game = repo.load(id)
val view = game.dropToRound(round)
view
}
case class Game(id:Int, events:List[GameEvent]){
def dropToRound(round:Int) = {
val newEvents = //events.filter() How? I need find index of "round"-th RoundStarted event and get all elements before it
this.copy(events = newEvents)
}
}
val testData = Game(1, List(RoundStarted//round 0, MessageSent, MessageSent, RoundStarted//round 1, MessageSent, RoundStarted//round 2))
//To retrieve all events before round 2 we calling load(1, 1)
assert(load(1, 1) shouldBe (Game(1,List(RoundStarted//round 0, MessageSent, MessageSent)))
I know how to do it imperatively, but what is the better way to acomplish it functionally? Preferrably without libs like scalaz, but if it really concise - I'll accept it as well:)
You can't actually use a filter since you want to collect events only until a specific condition occurs.
This function will collect the events:
def collectEvents(round: Int, events: List[GameEvent]): List[GameEvent] = {
def collectEventsList(r: Int, eventList: List[GameEvent], collectedEvents: List[GameEvent]): List[GameEvent] = {
eventList match {
case RoundStarted :: _ if r == 0 =>
collectedEvents
case RoundStarted :: y if r > 0 =>
collectEventsList(r - 1, y, RoundStarted :: collectedEvents)
case x :: y =>
collectEventsList(r, y, x :: collectedEvents)
case List() =>
collectedEvents
}
}
collectEventsList(round, events, List()).reverse
}
This is probably the worst of both worlds: it uses takeWhile together with mutable var. And it is pretty much equivalent to imperative solution. But at least it is short:
case class Game(id: Int, events: List[GameEvent]) {
def dropToRound(round: Int): Game = {
var cnt = 0
val newEvents = events.takeWhile({
case RoundStarted => cnt += 1
cnt <= round
case _ => true
})
this.copy(events = newEvents)
}
}
Update
Here is a more pure translation of the imperative code:
case class Game(id: Int, events: List[GameEvent]) {
def dropToRound(round: Int): Game = {
val newEvents = events.foldLeft((List.empty[GameEvent], 0))((t, ev) => (t, ev) match {
case ((out, cnt), _) if cnt > round => t
case ((out, cnt), RoundStarted) if cnt == round => t
case ((out, cnt), RoundStarted) => (ev :: out, cnt + 1)
case ((out, cnt), _) => (ev :: out, cnt)
})._1.reverse
this.copy(events = newEvents)
}
}
The obvious drawbacks are:
You can't stop foldLeft so it goes through the whole list of events anyway
Additional reverse at the end.

Working scala code using a var in a pure function. Is this possible without a var?

Is it possible (or even worthwhile) to try to write the below code block without a var? It works with a var. This is not for an interview, it's my first attempt at scala (came from java).
The problem: Fit people as close to the front of a theatre as possible, while keeping each request (eg. Jones, 4 tickets) in a single theatre section. The theatre sections, starting at the front, are sized 6, 6, 3, 5, 5... and so on. I'm trying to accomplish this by putting together all of the potential groups of ticket requests, and then choosing the best fitting group per section.
Here are the classes. A SeatingCombination is one possible combination of SeatingRequest (just the IDs) and the sum of their ticketCount(s):
class SeatingCombination(val idList: List[Int], val seatCount: Int){}
class SeatingRequest(val id: Int, val partyName: String, val ticketCount: Int){}
class TheatreSection(val sectionSize: Int, rowNumber: Int, sectionNumber: Int) {
def id: String = rowNumber.toString + "_"+ sectionNumber.toString;
}
By the time we get to the below function...
1.) all of the possible combinations of SeatingRequest are in a list of SeatingCombination and ordered by descending size.
2.) all of the TheatreSection are listed in order.
def getSeatingMap(groups: List[SeatingCombination], sections: List[TheatreSection]): HashMap[Int, TheatreSection] = {
var seatedMap = new HashMap[Int, TheatreSection]
for (sect <- sections) {
val bestFitOpt = groups.find(g => { g.seatCount <= sect.sectionSize && !isAnyListIdInMap(seatedMap, g.idList) })
bestFitOpt.filter(_.idList.size > 0).foreach(_.idList.foreach(seatedMap.update(_, sect)))
}
seatedMap
}
def isAnyListIdInMap(map: HashMap[Int, TheatreSection], list: List[Int]): Boolean = {
(for (id <- list) yield !map.get(id).isEmpty).reduce(_ || _)
}
I wrote the rest of the program without a var, but in this iterative section it seems impossible. Maybe with my implementation strategy it's impossible. From what else I've read, a var in a pure function is still functional. But it's been bothering me I can't think of how to remove the var, because my textbook told me to try to avoid them, and I don't know what I don't know.
You can use foldLeft to iterate on sections with a running state (and again, inside, on your state to add iteratively all the ids in a section):
sections.foldLeft(Map.empty[Int, TheatreSection]){
case (seatedMap, sect) =>
val bestFitOpt = groups.find(g => g.seatCount <= sect.sectionSize && !isAnyListIdInMap(seatedMap, g.idList))
bestFitOpt.
filter(_.idList.size > 0).toList. //convert option to list
flatMap(_.idList). // flatten list from option and idList
foldLeft(seatedMap)(_ + (_ -> sect))) // add all ids to the map with sect as value
}
By the way, you can simplify the second method using exists and map.contains:
def isAnyListIdInMap(map: HashMap[Int, TheatreSection], list: List[Int]): Boolean = {
list.exists(id => map.contains(id))
}
list.exists(predicate: Int => Boolean) is a Boolean which is true if the predicate is true for any element in list.
map.contains(key) checks if map is defined at key.
If you want to be even more concise, you don't need to give a name to the argument of the predicate:
list.exists(map.contains)
Simply changing var to val should do it :)
I think, you may be asking about getting rid of the mutable map, not of the var (it doesn't need to be var in your code).
Things like this are usually written recursively in scala or using foldLeft, like other answers suggest. Here is a recursive version:
#tailrec
def getSeatingMap(
groups: List[SeatingCombination],
sections: List[TheatreSection],
result: Map[Int, TheatreSection] = Map.empty): Map[Int, TheatreSection] = sections match {
case Nil => result
case head :: tail =>
val seated = groups
.iterator
.filter(_.idList.nonEmpty)
.filterNot(_.idList.find(result.contains).isDefined)
.find(_.seatCount <= head.sectionSize)
.fold(Nil)(_.idList.map(id => id -> sect))
getSeatingMap(groups, tail, result ++ seated)
}
btw, I don't think you need to test every id in list for presence in the map - should suffice to just look at the first one. You could also make it a bit more efficient, probably, if instead of checking the map every time to see if the group is already seated, you'd just drop it from the input list as soon as the section is assigned.
#tailrec
def selectGroup(
sect: TheatreSection,
groups: List[SeatingCombination],
result: List[SeatingCombination] = Nil
): (List[(Int, TheatreSection)], List[SeatingCombination]) = groups match {
case Nil => (Nil, result)
case head :: tail
if(head.idList.nonEmpty && head.seatCount <= sect.sectionSize) => (head.idList.map(_ -> sect), result.reverse ++ tail)
case head :: tail => selectGroup(sect, tail, head :: result)
}
and then in getSeatingMap:
...
case head :: tail =>
val(seated, remaining) => selectGroup(sect, groups)
getSeatingMap(remaining, tail, result ++ seated)
Here is how I was able to achieve without using the mutable.HashMap, the suggestion by the comment to use foldLeft was used to do it:
class SeatingCombination(val idList: List[Int], val seatCount: Int){}
class SeatingRequest(val id: Int, val partyName: String, val ticketCount: Int){}
class TheatreSection(val sectionSize: Int, rowNumber: Int, sectionNumber: Int) {
def id: String = rowNumber.toString + "_"+ sectionNumber.toString;
}
def getSeatingMap(groups: List[SeatingCombination], sections: List[TheatreSection]): Map[Int, TheatreSection] = {
sections.foldLeft(Map.empty[Int, TheatreSection]) { (m, sect) =>
val bestFitOpt = groups.find(g => {
g.seatCount <= sect.sectionSize && !isAnyListIdInMap(m, g.idList)
}).filter(_.idList.nonEmpty)
val newEntries = bestFitOpt.map(_.idList.map(_ -> sect)).getOrElse(List.empty)
m ++ newEntries
}
}
def isAnyListIdInMap(map: Map[Int, TheatreSection], list: List[Int]): Boolean = {
(for (id <- list) yield map.get(id).isDefined).reduce(_ || _)
}