Find common items in two lists (Scala) - scala

A newbie Scala question .
I'm trying to implement a function that receive two Lists ,find a common item , than make manipulation and create a new list
I have a case class
case class weightedFruits(fruits: Set[String], weight: Double)
and two lists weightedFruitsList and filteredWeightedFruitsList:
// set is sorted
val weightedFruitsList = List(
weightedFruits(Set("banana"), 200),
weightedFruits(Set("banana", "orange"), 180),
weightedFruits(Set("banana", "orange", "apple"), 170),
weightedFruits(Set("feijoa", "fig"), 201))
//filtered List , Set sorted, contains "melon" as last member
val filteredWeightedFruitsList = List(
weightedFruits(Set("banana", "melon"), 250),
weightedFruits(Set("banana", "orange", "melon"), 270),
weightedFruits(Set("banana", "orange", "apple", "melon"), 365))
I'd like to go over each item in filteredWeightedFruitsList , find same items in weightedFruitsList, do a small manipulation and create a new List[weightedFruits]
My (not working yet) code :
def conf :Option[List[weightedFruits]] = {
for (filtered <- filteredWeightedFruitsList){
weightedFruitsList.find{
case x if ( x.fruits equals filtered.fruits.dropRight(1) ) => return weightedFruits(x.fruits, x.weight / filtered.weight)]
case _ => false
}
}
}
With this code I've two problems:
1) type mismatch; found : Unit required: Option
2) type mismatch; found : weightedFruits required: Option[List[weightedFruits]]
Any thoughts are welcome . Sorry if my question make you mad...
Last question maybe there is more efficient way to make this task ?
Thanks

type mismatch; found : weightedFruits required: Option[List[weightedFruits]] is caused by your conf method doesn't return Option[List[weightedFruits]] type result. maybe you can try use for yield to do this.
def conf :List[weightedFruits] = for {
f <- filteredWeightedFruitsList
t <- weightedFruitsList.find(i => f.fruits.dropRight(1) == i.fruits)
} yield t.copy(weight = t.weight / f.weight)
copy method will copy case class, and override some fields by using name

Related

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

Update (or Replace) item(s) in immutable collection in Scala

What is best practice to update (or replace) a item in Seq ?
case class Minion(id: Int, name: String, motivation: Int)
val minions: Seq[Minion] = Seq(
Minion(1, "Bob", 50),
Minion(2, "Kevin", 50),
Minion(3, "Stuart", 50))
I'd like to acquire new Collection
Seq(
Minion(1, "Bob", 50),
Minion(2, "Kevin", 50),
Minion(3, "Stuart", 100))
What's best way ?
Use updated:
// first argument is index (zero-based) - so using 2 to replace 3rd item:
scala> minions.updated(2, Minion(3, "Stuart", 100))
res0: Seq[Minion] = List(Minion(1,Bob,50), Minion(2,Kevin,50), Minion(3,Stuart,100))
Or, without repeating the unchanged attributes of the new Minion:
scala> minions.updated(2, minions(2).copy(motivation = 100))
res1: Seq[Minion] = List(Minion(1,Bob,50), Minion(2,Kevin,50), Minion(3,Stuart,100))
Map also works, and might be a little bit easier to read than updated:
minions.map {
case Minion(2, name, n) => Minion(2, name, 100)
case m => m
}
One benefit of this over updated besides readability is that you can modify several elements in one go.

Type Mismatch in scala case match

Trying to create multiple dataframes in a single foreach, using spark, as below
I get values delivery and click out of row.getAs("type"), when I try to print them.
val check = eachrec.foreach(recrd => recrd.map(row => {
row.getAs("type") match {
case "delivery" => val delivery_data = delivery(row.get(0).toString,row.get(1).toString)
case "click" => val click_data = delivery(row.get(0).toString,row.get(1).toString)
case _ => "not sure if this impacts"
}})
)
but getting below error:
Error:(41, 14) type mismatch; found : String("delivery") required: Nothing
case "delivery" => val delivery_data = delivery(row.get(0).toString,row.get(1).toString)
^
My plan is to create dataframe using todf() once I create these individual delivery objects referenced by delivery_data and click_data by:
delivery_data.toDF() and click_data.toDF().
Please provide any clue regarding the error above (in match case).
How can I create two df's using todf() in val check?
val declarations make your first 2 cases return type to be unit, but in the third case you return a String
for instance, here the z type was inferred by the compiler, Unit:
def x = {
val z: Unit = 3 match {
case 2 => val a = 2
case _ => val b = 3
}
}
I think you need to cast this match clause to String.
row.getAs("type").toString

How to get a List of Maps from a List of Objects in Scala

I need some help with Scala. I really have troubles in understanding how to deal with collections. What I have to do is traversing a List like this
List( MyObject(id, name, status), ..., MyObject(id, name, status) )
and getting another List like this one
List( Map("key", id1), Map("key", id2), ..., Map("key", idN) )
Notice that the 'key' element of all the maps have to be the same
Thanks
you can use the map function to transform a list of MyObject to a list of Map by:
val list = List( MyObject(id, name, status), ..., MyObject(id, name, status) )
val result = list map {o => Map("key" -> o.id)}
scala school from twitter is a good reading for beginners, and if you want to know the architecture of the Scala collections framework in detail, please refer to scala doc
I think this should do it.
list map { x => Map( "key" -> x.id ) }
An example
scala> case class Tst (fieldOne : String, fieldTwo : String)
defined class Tst
scala> val list = List(Tst("x", "y"), Tst("z", "a"))
list: List[Tst] = List(Tst(x,y), Tst(z,a))
list map { x => Map( "key" -> x.fieldOne ) }
res6: List[scala.collection.immutable.Map[String,String]] = List(Map(key -> y), Map(key -> a))

Returning an element from a List in Scala

I've recently been working on a beginner's project in Scala, and have a beginner question about Scala's Lists.
Say I have a list of tuples ( List[Tuple2[String, String]], for example). Is there a convenience method to return the first occurence of a specified tuple from the List, or is it necessary to iterate through the list by hand?
scala> val list = List(("A", "B", 1), ("C", "D", 1), ("E", "F", 1), ("C", "D", 2), ("G", "H", 1))
list: List[(java.lang.String, java.lang.String, Int)] = List((A,B,1), (C,D,1), (E,F,1), (C,D,2), (G,H,1))
scala> list find {e => e._1 == "C" && e._2 == "D"}
res0: Option[(java.lang.String, java.lang.String, Int)] = Some((C,D,1))
You could try using find. (Updated scala-doc location of find)
As mentioned in a previous comment, find is probably the easiest way to do this. There are actually three different "linear search" methods in Scala's collections, each returning a slightly different value. Which one you use depends upon what you need the data for. For example, do you need an index, or do you just need a boolean true/false?
If you're learning scala, I'd take a good look at the Seq trait. It provides the basis for much of scala's functional goodness.
You could also do this, which doesn't require knowing the field names in the Tuple2 class--it uses pattern matching instead:
list find { case (x,y,_) => x == "C" && y == "D" }
"find" is good when you know you only need one; if you want to find all matching elements you could either use "filter" or the equivalent sugary for comprehension:
for ( (x,y,z) <- list if x == "C" && y == "D") yield (x,y,z)
Here's code that may help you.
I had a similar case, having a collection of base class entries (here, A) out of which I wanted to find a certain derived class's node, if any (here, B).
class A
case class B(val name: String) extends A
object TestX extends App {
val states: List[A] = List( B("aa"), new A, B("ccc") )
def findByName( name: String ): Option[B] = {
states.find{
case x: B if x.name == name => return Some(x)
case _ => false
}
None
}
println( findByName("ccc") ) // "Some(B(ccc))"
}
The important part here (for my app) is that findByName does not return Option[A] but Option[B].
You can easily modify the behaviour to return B instead, and throw an exception if none was found. Hope this helps.
Consider collectFirst which delivers Some[(String,String)] for the first matching tuple or None otherwise, for instance as follows,
xs collectFirst { case t#(a,_) if a == "existing" => t }
Some((existing,str))
scala> xs collectFirst { case t#(a,_) if a == "nonExisting" => t }
None
Using # we bind the value of the tuple to t so that a whole matching tuple can be collected.