[英]Rewrite scala code to be more functional
我試圖自學Scala,同時嘗試編寫功能語言慣用的代碼,即編寫更好,更優雅的功能代碼。
我有下面的代碼可以正常工作:
import org.apache.spark.SparkConf
import org.apache.spark.sql.{DataFrame, SparkSession}
import java.time.LocalDate
object DataFrameExtensions_ {
implicit class DataFrameExtensions(df: DataFrame){
def featuresGroup1(groupBy: Seq[String], asAt: LocalDate): DataFrame = {df}
def featuresGroup2(groupBy: Seq[String], asAt: LocalDate): DataFrame = {df}
}
}
import DataFrameExtensions_._
val spark = SparkSession.builder().config(new SparkConf().setMaster("local[*]")).enableHiveSupport().getOrCreate()
import spark.implicits._
val df = Seq((8, "bat"),(64, "mouse"),(-27, "horse")).toDF("number", "word")
val groupBy = Seq("a","b")
val asAt = LocalDate.now()
val dataFrames = Seq(df.featuresGroup1(groupBy, asAt),df.featuresGroup2(groupBy, asAt))
最后一行雖然困擾我。 這兩個函數( featuresGroup1
, featuresGroup2
)都具有相同的簽名:
scala> :type df.featuresGroup1(_,_)
(Seq[String], java.time.LocalDate) => org.apache.spark.sql.DataFrame
scala> :type df.featuresGroup2(_,_)
(Seq[String], java.time.LocalDate) => org.apache.spark.sql.DataFrame
並使用與參數相同的val
,因此我假設我可以以一種更具功能性的方式(可能以某種方式使用.map
)來寫那行,這意味着我可以只編寫一次參數列表並將其傳遞給兩個函數。 我無法弄清楚語法。 我以為也許可以構造一個這些功能的列表,但這不起作用:
scala> Seq(featuresGroup1, featuresGroup2)
<console>:23: error: not found: value featuresGroup1
Seq(featuresGroup1, featuresGroup2)
^
<console>:23: error: not found: value featuresGroup2
Seq(featuresGroup1, featuresGroup2)
^
有人可以幫忙嗎?
我以為也許可以構造這些功能的列表,但是那沒用
您需要通過使用下划線運算符來顯式執行eta擴展,以將方法轉換為函數(在Scala中不同)。
val funcs = Seq(featuresGroup1 _, featuresGroup2 _)
或使用占位符:
val funcs = Seq(featuresGroup1(_, _), featuresGroup2(_, _))
而且,使用map
運算符絕對正確:
val dataFrames = funcs.map(f => f(groupBy, asAdt))
我強烈建議您不要使用String
或Seq
類型的隱式Seq
,就好像在多個地方使用它們一樣,它們也會導致細微的錯誤,這些錯誤從代碼中不會立即顯而易見,並且在將代碼移至某個位置時,代碼很容易被破壞。
如果要使用隱式,請將它們包裝到自定義類型中:
case class DfGrouping(groupBy: Seq[String]) extends AnyVal
implicit val grouping: DfGrouping = DfGrouping(Seq("a", "b"))
我以為也許可以構造一個這些功能的列表,但這不起作用:
當上面已經有正確的語法df.featuresGroup1(_,_)
時,為什么在這里只寫featuresGroup1/2
?
Seq(df.featuresGroup1(_,_), df.featuresGroup2(_,_)).map(_(groupBy, asAt))
df.featuresGroup1 _
應該工作。
如果您具有預期的類型,則df.featuresGroup1
本身可以工作,例如
val dataframes: Seq[(Seq[String], LocalDate) => DataFrame] =
Seq(df.featuresGroup1, df.featuresGroup2)
但是在這種特定情況下,提供期望的類型比使用lambda更冗長。
為什么不只是在DataFrameExtensions
創建一個函數呢?
def getDataframeGroups(groupBy: Seq[String], asAt: String) = Seq(featuresGroup1(groupBy,asAt), featuresGroup2(groupBy,asAt))
我認為您可以創建如下功能列表:
val funcs:List[DataFrame=>(Seq[String], java.time.LocalDate) => org.apache.spark.sql.DataFrame] = List(_.featuresGroup1, _.featuresGroup1)
funcs.map(x => x(df)(groupBy, asAt))
似乎您有將一個DataFrame
轉換為另一個DataFrame
的函數列表。 如果是這樣的話,您可以在Scalaz
與Endo
一起Scalaz
我最喜歡這個答案,這是由Alexey Romanov提供的。
import org.apache.spark.SparkConf
import org.apache.spark.sql.{DataFrame, SparkSession}
import java.time.LocalDate
object DataFrameExtensions_ {
implicit class DataFrameExtensions(df: DataFrame){
def featuresGroup1(groupBy: Seq[String], asAt: LocalDate): DataFrame = {df}
def featuresGroup2(groupBy: Seq[String], asAt: LocalDate): DataFrame = {df}
}
}
import DataFrameExtensions_._
val spark = SparkSession.builder().config(new SparkConf().setMaster("local[*]")).enableHiveSupport().getOrCreate()
import spark.implicits._
val df = Seq((8, "bat"),(64, "mouse"),(-27, "horse")).toDF("number", "word")
val groupBy = Seq("a","b")
val asAt = LocalDate.now()
Seq(df.featuresGroup1(_,_), df.featuresGroup2(_,_)).map(_(groupBy, asAt))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.