I have a case class as follow:
case class AGG_RECON_4( var VOL_PROBE_DL_VOL:Int, var VOL_PROBE_FREE_VOL:Int, var VOL_PROBE_TOT_VOL:Int, VOL_NW_UL_VOL:Int,VOL_NW_DL_VOL:Int, VOL_NW_FREE_VOL:Int, VOL_NW_TOT_VOL:Int, VOL_CHG_UL_VOL:Int,
VOL_CHG_DL_VOL:Int, VOL_CHG_FREE_VOL:Int, VOL_CHG_TOT_VOL:Int, VOL_DXE_Session_End_Time:String, VOL_NW_Session_End_Time:String,
VOL_CHG_Session_End_Time:String, VOL_Session_Closed_Time:String, VOL_DXE_Is_Completed:Boolean, VOL_NW_Is_Completed:Boolean, VOL_CHG_Is_Completed:Boolean, VOL_Is_Closed:Boolean, VOL_Session_Category:String) extends Serializable
case class AGG_RECON_3( CHG_ROAM_TYPE:String, CHG_APN:String,
CHG_APN_Category:String, CHG_Charging_Characteristics:String, CHG_Rate_Plan:String, CHG_Rating_Group:String, var CHG_CDR_Count:Int, var VOL_PROBE_UL_VOL:Int) extends Serializable
case class AGG_RECON_2(NW_First_Report_Time:String, NW_Last_Report_Time:String, NW_Session_Start_Time:String, NW_IMSI:String, NW_MSISDN:String, NW_RAT_Type:String, NW_ROAM_TYPE:String, NW_APN:String, NW_APN_Category:String, NW_Charging_Characteristics:String, var NW_CDR_Count:Int,
CHG_First_Report_Time:String, CHG_Last_Report_Time:String, CHG_Session_Start_Time:String, CHG_IMSI:String, CHG_MSISDN:String) extends Serializable
case class AGG_RECON(SUBSCRIBER_ID:String, ChargingID:String ,NodeID:String, START_TIME:String, DXE_First_Report_Time:String, DXE_Last_Report_Time:String, DXE_Session_Start_Time:String, DXE_Bearer_Creation_Time:String, DXE_IMSI:String, DXE_MSISDN:String, DXE_RAT_Type:String,
DXE_Subscriber_Type:String, DXE_VPMN:String, DXE_ROAM_TYPE:String, DXE_APN:String, DXE_APN_Category:String, DXE_Charging_Characteristics:String,var DXE_CDR_Count:Int,agg_recon_2:AGG_RECON_2,agg_recon_3:AGG_RECON_3,agg_recon_4:AGG_RECON_4) extends Ordered[AGG_RECON] with Serializable
{
def compare(that: AGG_RECON): Int = {
var formatter: DateTimeFormatter = null
var d1: DateTime= //..
var d2: DateTime =//..
return d1.compareTo(d2)
}
}
I go then alist of my case class instances; however, when I try to sort it:
val elements=//Array[AGG_RECONN]
val sorted_cdrs=elements().sorted[AGG_RECON]
I got : No implicit Ordering defined for AGG_RECON.
Do not implement Ordered in AGG_RECON. Instead, define an implicit Ordering[AGG_RECON] like this:
object AGG_RECON {
implicit object AGG_RECON_Ordering extends Ordering[AGG_RECON] {
override def compare(x: AGG_RECON, y: AGG_RECON) = ??? // Compare x and y
}
}
(Side note: Is it really necessary to use UPPER_CASE names? It really clashes with convention.)
Related
I need to write two functions to get the output format and the output index for file conversion. As part of this, I wrote a TransformSettings class for these methods and set the default value. And in the transformer class, I created a new object of TransformSettings class to get the default values for each job run. Also, I have another class called ParquetTransformer that extends Transformer where I want to change these default values. So I implemented like below.
class TransformSettings{
def getOuputFormat: String = {
"orc"
}
def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("orc.column.index.access")
}
}
class Transformer{
def getTransformSettings: TransformSettings = {
new TransformSettings
}
def posttransform(table: AWSGlueDDL.Table):Dateframe ={
val indexAccess = getTransformSettings.getOuputIndex(table: AWSGlueDDL.Table)
........
}
}
class ParquetTransformer extends Transformer{
override def getTransformSettings: TransformSettings = {
val transformSettings = new TransformSettings {
override def getOuputFormat: String = {
"parquet"
}
override def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("parquet.column.index.access")
}
}
}
}
Is there a way to avoid creating a brand new object of TransformSettings in Transfomer class every time this is called?
Also is there a way to rewrite the code using Scala value class?
As #Dima proposed in the comments try to make TransformSettings a field / constructor parameter (a val) in the class Transformer and instantiate them outside
class TransformSettings{
def getOuputFormat: String = {
"orc"
}
def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("orc.column.index.access")
}
}
class Transformer(val transformSettings: TransformSettings) {
def posttransform(table: AWSGlueDDL.Table): DataFrame ={
val indexAccess = transformSettings.getOuputIndex(table: AWSGlueDDL.Table)
???
}
}
val parquetTransformSettings = new TransformSettings {
override def getOuputFormat: String = {
"parquet"
}
override def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("parquet.column.index.access")
}
}
class ParquetTransformer extends Transformer(parquetTransformSettings)
You don't seem to need value classes (... extends AnyVal) now. They are more about unboxing, not about life-cycle management. TransformSettings and Transformer can't be value classes because they are not final (you're extending them in class ParquetTransformer extends Transformer... and new TransformSettings { ... }). By the way, value classes have many limatations
https://failex.blogspot.com/2017/04/the-high-cost-of-anyval-subclasses.html
https://github.com/scala/bug/issues/12271
Besides value classes, there are scala-newtype library in Scala 2 and opaque types in Scala 3.
I want to print the contents of a collection and I've tried with the mkString method, but it gives me still not the right content of the object.
My code:
package org.template
import org.apache.predictionio.controller.LServing
class Serving
extends LServing[Query, PredictedResult] {
override
def serve(query: Query,
predictedResults: Seq[PredictedResult]): PredictedResult = {
println(predictedResults.mkString("\n"))
predictedResults.head
}
}
The response:
predictedResult([Lorg.template.ItemScore;#2fb3a837,[Lorg.template.Rule;#5cfc70a8)
Definition of the PredictedResult class:
package org.template
import org.apache.predictionio.controller.EngineFactory
import org.apache.predictionio.controller.Engine
// Query most similar (top num) items to the given
case class Query(items: Set[String], num: Int) extends Serializable
case class PredictedResult(itemScores: Array[ItemScore], rules: Array[Rule]) extends Serializable
If PredictedResult is a case class like so
case class PredictedResult(value: String)
val predictedResults = List(PredictedResult("aaa"), PredictedResult("bbb"))
println(predictedResults.mkString("\n"))
then we get nice output
PredictedResult(aaa)
PredictedResult(bbb)
However if it is a regular class like so
class PredictedResult(value: String)
val predictedResults = List(new PredictedResult("aaa"), new PredictedResult("bbb"))
println(predictedResults.mkString("\n"))
then we get
example.Hello$PredictedResult#566776ad
example.Hello$PredictedResult#6108b2d7
To get the nice output for regular class we need to override its toString method like so
class PredictedResult(value: String) {
override def toString: String = s"""PredictedResult($value)"""
}
which now outputs
PredictedResult(aaa)
PredictedResult(bbb)
Addressing the comment we have
case class Rule(v: String)
case class ItemScore(v: Int)
case class PredictedResult(itemScores: Array[ItemScore], rules: Array[Rule]) {
override def toString: String =
s"""
|PredictedResult(Array(${itemScores.mkString(",")}, Array(${rules.mkString(",")}))
""".stripMargin
}
val predictedResults = List(PredictedResult(Array(ItemScore(42), ItemScore(11)), Array(Rule("rule1"), Rule("rule2"))))
println(predictedResults.mkString("\n"))
which outputs
PredictedResult(Array(ItemScore(42),ItemScore(11), Array(Rule(rule1),Rule(rule2)))
If we change from Array to List like so
case class Rule(v: String)
case class ItemScore(v: Int)
case class PredictedResult(itemScores: List[ItemScore], rules: List[Rule])
val predictedResults = List(PredictedResult(List(ItemScore(42), ItemScore(11)), List(Rule("rule1"), Rule("rule2"))))
println(predictedResults.mkString("\n"))
then we get nice output out-of-the-box without the need to override toString
PredictedResult(List(ItemScore(42), ItemScore(11)),List(Rule(rule1), Rule(rule2)))
I have something like this:
abstract class HaveData{
val data:String
}
class HD1 extends HaveData{
val data = "HD1 data"
}
class HD2 extends HaveData{
val data = "HD2 data"
object InnerHD extends HD1{
def prt = println(data)
}
}
I want to print "HD2 data" not "HD1 data", how to do that?
I may turn InnerHD to a class and provide data as a param but is there a better way?
For this kind of situations you can use a self-type, for this specific problem, you do not need to add a different type.
abstract class HaveData {
def data: String
}
class HD1 extends HaveData {
override val data = "HD1 data"
}
class HD2 extends HaveData { self => // Alias to this in the HD2 level.
override val data = "HD2 data"
object InnerHD extends HD1 {
def prt(): Unit = {
println(self.data)
}
}
}
(new HD2).InnerHD.prt()
// HD2 data
You can also use
def prt = println(HD2.this.data)
So I made a post earlier about accessing a field of a subclass from within the superclass to solve a problem i have. But they made it clear that it is practically impossible. So I made a little example of what i want to achieve:
abstract class LotteryTicket(val numbers: String) {
val price: Int
}
//The numbers are different for each ticket and are used to denote a winner in the end.
class GoldTicket(numbers: String) extends LotteryTicket(person) {
val price: Int = 10
}
class SilverTicket(numbers: String) extends LotteryTicket(person) {
val price: Int = 5
}
abstract class Drink {
val price: Int
}
object Water extends Drink {
val price: Int = 1
}
object Coffee extends Drink {
val price: Int = 2
}
class Bill
class Customer
The class 'Bill' should contain a list which can include Drinks as well as LotteryTickets, for which the total can be calculated and the Customer has to be able to make such a bill. The Customer class also needs a method which confirms the purchase and checks if the numbers on his LottoryTicket are different for every Ticket he bought. Because when he has the same number on 2 tickets The confirmation fails. It alse must be possible to add new products in the future (like food for example) in an easy way (without changing the core code).
You want your "billable" items implement a trait, that exposes their common features.
trait Billable {
def price: Int
}
class LotteryTicket(val numbers: String, val price: Int) extends Billable
class GoldTicket(n: String) extends LotteryTicket(n, 10)
class SilverTockent(n: String) extends LotteryTicket(n, 5)
class Drink(val price: Int) extends Billable
object Water extends Drink(1)
object Coffee extends Drink(2)
case class Bill(val items: Seq[Billable]= Seq.empty)
{
def amount = items.map(_.price).sum
def add(b: Billable) = copy(b +: items)
}
case class Customer(bill: Bill = Bill()) {
def buy(ticket: LotteryTicket) = {
// validate numbers, whatever
Customer(bill.add(ticket))
}
def buy(drink: Drink) = {
Customer(bill.add(drink)
}
def howMuch = bill.total
def validateAllTickets = bill.items.foreach {
case ticket: LotteryTicket => makeSureNumberIsGood(ticket.numbers)
case _ =>
}
}
A solution for the Bill class using the Dima's classes :
class BillImplementation {
private var container = Seq[Billable]()
def addProduct(product: Billable) = container :+= product // this add the product element to the container Seq
def listOfAllBillableInThis = container
def totalSum = container.map(_.price).sum
def isThere2ticketsWithSameNumbers: Boolean = {
var containerOfTickets = Seq[LotteryTicket]()
for (p <- container) {
p match {
case lo: LotteryTicket => containerOfTickets = containerOfTickets :+ lo
case _ =>
}
}
val numbersMap = containerOfTickets.map(_.n)
numbersMap.distinct.size != numbersMap.size
}
def empty: Unit = container = Nil
}
And do not use Int for prices but BigDecimal.
I have a number of classes that look like this:
class Foo(val:BasicData) extends Bar(val) {
val helper = new Helper(val)
val derived1 = helper.getDerived1Value()
val derived2 = helper.getDerived2Value()
}
...except that I don't want to hold onto an instance of "helper" beyond the end of the constructor. In Java, I'd do something like this:
public class Foo {
final Derived derived1, derived2;
public Foo(BasicData val) {
super(val);
Helper helper = new Helper(val);
derived1 = helper.getDerived1Value();
derived2 = helper.getDerived2Value();
}
}
So how do I do something like that in Scala? I'm aware of creating a helper object of the same name of the class with an apply method: I was hoping for something slightly more succinct.
You could use a block to create a temporary helper val and return a tuple, like this:
class Foo(v: BasicData) extends Bar(v) {
val (derived1, derived2) = {
val helper = new Helper(v)
(helper.getDerived1Value(), helper.getDerived2Value())
}
}
Better look at the javap output (including private members) before you conclude this has side-stepped any fields for the Tuple2 used in the intermediate pattern-matching.
As of Scala 2.8.0.RC2, this Scala code (fleshed out to compile):
class BasicData
{
def basic1: Int = 23
def basic2: String = "boo!"
}
class Helper(v: BasicData)
{
def derived1: Int = v.basic1 + 19
def derived2: String = v.basic2 * 2
}
class Bar(val v: BasicData)
class Foo(v: BasicData)
extends Bar(v)
{
val (derived1, derived2) = {
val helper = new Helper(v)
(helper.derived1, helper.derived2)
}
}
Produces this Foo class:
% javap -private Foo
public class Foo extends Bar implements scala.ScalaObject{
private final scala.Tuple2 x$1;
private final int derived1;
private final java.lang.String derived2;
public int derived1();
public java.lang.String derived2();
public Foo(BasicData);
}