coder25
coder25

Reputation: 2393

Filter a list based on a parameter

I want to filter the employees based on name and return the id of each employee

case class Company(emp:List[Employee])
  case class Employee(id:String,name:String)

  val emp1=Employee("1","abc")
  val emp2=Employee("2","def")

  val cmpy= Company(List(emp1,emp2))

  val a = cmpy.emp.find(_.name == "abc")
  val b = a.map(_.id)
  val c = cmpy.emp.find(_.name == "def")
  val d = c.map(_.id)

  println(b)
  println(d)

I want to create a generic function that contains the filter logic and I can have different kind of list and filter parameter for those list

Ex employeeIdByName which takes the parameters

Updated

Any better way to achieve the result I have used map and find

Upvotes: 0

Views: 1398

Answers (2)

Tzach Zohar
Tzach Zohar

Reputation: 37822

If you really want a "generic" filter function, that can filter any list of elements, by any property of these elements, based on a closed set of "allowed" values, while mapping results to some other property - it would look something like this:

def filter[T, P, R](
    list: List[T],          // input list of elements with type T (in our case: Employee)
    propertyGetter: T => P, // function extracting value for comparison, in our case a function from Employee to String
    values: List[P],        // "allowed" values for the result of propertyGetter
    resultMapper: T => R    // function extracting result from each item, in our case from Employee to String
): List[R] = {
  list
    // first we filter only items for which the result of 
    // applying "propertyGetter" is one of the "allowed" values:
    .filter(item => values.contains(propertyGetter(item)))
    // then we map remaining values to the result using the "resultMapper"
    .map(resultMapper)
}

// for example, we can use it to filter by name and return id:
filter(
  List(emp1, emp2), 
  (emp: Employee) => emp.name, // function that takes an Employee and returns its name
  List("abc"), 
  (emp: Employee) => emp.id // function that takes an Employee and returns its id
)
// List(1)

However, this is a ton of noise around a very simple Scala operation: filtering and mapping a list; This specific usecase can be written as:

val goodNames = List("abc")
val input = List(emp1, emp2)

val result = input.filter(emp => goodNames.contains(emp.name)).map(_.id)

Or even:

val result = input.collect {
  case Employee(id, name) if goodNames.contains(name) => id
}

Scala's built-in map, filter, collect functions are already "generic" in the sense that they can filter/map by any function that applies to the elements in the collection.

Upvotes: 1

Ziyang Liu
Ziyang Liu

Reputation: 810

You can use Shapeless. If you have a employees: List[Employee], you can use

import shapeless._
import shapeless.record._

employees.map(LabelledGeneric[Employee].to(_).toMap)

To convert each Employee to a map from field key to field value. Then you can apply the filters on the map.

Upvotes: 0

Related Questions