Scala 如何计算';n';功能样式中的天间隔日期?
我正在尝试计算从开始日期到结束日期的“n”天间隔。函数签名将以start_date、end_date、interval作为参数,返回包含给定间隔的开始、结束日期列表的映射Scala 如何计算';n';功能样式中的天间隔日期?,scala,functional-programming,Scala,Functional Programming,我正在尝试计算从开始日期到结束日期的“n”天间隔。函数签名将以start_date、end_date、interval作为参数,返回包含给定间隔的开始、结束日期列表的映射 Example: start_date:2018-01-01 , End_date : 2018-02-20 interval: 20 import java.time.LocalDate def generateDates( startDate :LocalDate , endDat
Example: start_date:2018-01-01 , End_date : 2018-02-20 interval: 20
import java.time.LocalDate
def generateDates( startDate :LocalDate
, endDate :LocalDate
, dayInterval :Int ) :Unit = {
val intervals =
Stream.iterate((startDate, startDate plusDays dayInterval-1)){
case (_,lastDate) =>
val nextDate = lastDate plusDays dayInterval
(lastDate plusDays 1, if (nextDate isAfter endDate) endDate
else nextDate)
}.takeWhile(_._1 isBefore endDate)
println(intervals.mkString("\n"))
}
预期输出:
2018-01-012018-01-20(20天)
2018-01-212018-02-09(20天)
2018-02-092018-01-20(剩余)
我试着用scala写作,但我觉得这不是一种合适的功能性写作风格
case class DateContainer(period: String, range: (LocalDate, LocalDate))
def generateDates(startDate: String, endDate: String,interval:Int): Unit = {
import java.time._
var lstDDateContainer = List[DateContainer]()
var start = LocalDate.parse(startDate)
val end = LocalDate.parse(endDate)
import java.time.temporal._
var futureMonth = ChronoUnit.DAYS.addTo(start, interval)
var i = 1
while (end.isAfter(futureMonth)) {
lstDDateContainer = DateContainer("P" + i, (start, futureMonth)):: lstDDateContainer
start=futureMonth
futureMonth = ChronoUnit.DAYS.addTo(futureMonth, interval)
i += 1
}
lstDDateContainer= DateContainer("P" + i, (start, end))::lstDDateContainer
lstDDateContainer.foreach(println)
}
generateDates("2018-01-01", "2018-02-20",20)
谁能帮我写一个功能性的风格。类似(未经测试):
类似于(未经测试):
如果你的电脑可以用来处理日期时间的话,下面是我使用的
import org.joda.time.{DateTime, Days}
// given from & to dates, find no of days elapsed in between (integer)
def getDaysInBetween(from: DateTime, to: DateTime): Int = Days.daysBetween(from, to).getDays
def getDateSegments(from: DateTime, to: DateTime, interval: Int): Seq[(DateTime, DateTime)] = {
// no of days between from & to dates
val days: Int = DateTimeUtils.getDaysInBetween(from, to) + 1
// no of segments (date ranges) between to & from dates
val segments: Int = days / interval
// (remaining) no of days in last range
val remainder: Int = days % interval
// last date-range
val remainderRanges: Seq[(DateTime, DateTime)] =
if (remainder != 0) from -> from.plusDays(remainder - 1) :: Nil
else Nil
// all (remaining) date-ranges + last date-range
(0 until segments).map { segment: Int =>
to.minusDays(segment * interval + interval - 1) -> to.minusDays(segment * interval)
} ++ remainderRanges
}
如果你的电脑可以用来处理日期时间的话,下面是我使用的
import org.joda.time.{DateTime, Days}
// given from & to dates, find no of days elapsed in between (integer)
def getDaysInBetween(from: DateTime, to: DateTime): Int = Days.daysBetween(from, to).getDays
def getDateSegments(from: DateTime, to: DateTime, interval: Int): Seq[(DateTime, DateTime)] = {
// no of days between from & to dates
val days: Int = DateTimeUtils.getDaysInBetween(from, to) + 1
// no of segments (date ranges) between to & from dates
val segments: Int = days / interval
// (remaining) no of days in last range
val remainder: Int = days % interval
// last date-range
val remainderRanges: Seq[(DateTime, DateTime)] =
if (remainder != 0) from -> from.plusDays(remainder - 1) :: Nil
else Nil
// all (remaining) date-ranges + last date-range
(0 until segments).map { segment: Int =>
to.minusDays(segment * interval + interval - 1) -> to.minusDays(segment * interval)
} ++ remainderRanges
}
我提供的解决方案产生的结果与问题中给出的结果略有不同,但可以轻松修改以获得所需的答案:
//Preliminaries
val fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd")
val startDate ="2018-01-01"
val endDate = "2018-02-21"
val interval = 20L
val d1 = LocalDate.parse(startDate, fmt)
val d2 = LocalDate.parse(endDate, fmt)
//The main code
Stream.continually(interval)
.scanLeft((d1, d1.minusDays(1), interval)) ((x,y) => {
val finDate = x._2.plusDays(y)
if(finDate.isAfter(d2))
(x._2.plusDays(1), d2, ChronoUnit.DAYS.between(x._2, d2))
else
(x._2.plusDays(1), x._2.plusDays(y), y)
}).takeWhile(d => d._3 > 0).drop(1).toList
结果:
(2018-01-01,2018-01-20,20)
(2018-01-21,2018-02-09,20)
(2018-02-10,2018-02-21,12)
我们的想法是在
间隔流中扫描一个3元组,并在没有剩余天数时停止。我提供了一个解决方案,该解决方案产生的结果与问题中给出的结果略有不同,但可以轻松修改以获得所需的答案:
//Preliminaries
val fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd")
val startDate ="2018-01-01"
val endDate = "2018-02-21"
val interval = 20L
val d1 = LocalDate.parse(startDate, fmt)
val d2 = LocalDate.parse(endDate, fmt)
//The main code
Stream.continually(interval)
.scanLeft((d1, d1.minusDays(1), interval)) ((x,y) => {
val finDate = x._2.plusDays(y)
if(finDate.isAfter(d2))
(x._2.plusDays(1), d2, ChronoUnit.DAYS.between(x._2, d2))
else
(x._2.plusDays(1), x._2.plusDays(y), y)
}).takeWhile(d => d._3 > 0).drop(1).toList
结果:
(2018-01-01,2018-01-20,20)
(2018-01-21,2018-02-09,20)
(2018-02-10,2018-02-21,12)
其思想是通过间隔流扫描一个3元组,并在没有剩余天数时停止。使用java.time
库生成日期,使用stream.iterate()
生成间隔序列
Example: start_date:2018-01-01 , End_date : 2018-02-20 interval: 20
import java.time.LocalDate
def generateDates( startDate :LocalDate
, endDate :LocalDate
, dayInterval :Int ) :Unit = {
val intervals =
Stream.iterate((startDate, startDate plusDays dayInterval-1)){
case (_,lastDate) =>
val nextDate = lastDate plusDays dayInterval
(lastDate plusDays 1, if (nextDate isAfter endDate) endDate
else nextDate)
}.takeWhile(_._1 isBefore endDate)
println(intervals.mkString("\n"))
}
用法:
generateDates(LocalDate.parse("2018-01-01"), LocalDate.parse("2018-02-20"), 20)
// (2018-01-01,2018-01-20)
// (2018-01-21,2018-02-09)
// (2018-02-10,2018-02-20)
使用java.time
库生成日期,使用Stream.iterate()
生成间隔序列
Example: start_date:2018-01-01 , End_date : 2018-02-20 interval: 20
import java.time.LocalDate
def generateDates( startDate :LocalDate
, endDate :LocalDate
, dayInterval :Int ) :Unit = {
val intervals =
Stream.iterate((startDate, startDate plusDays dayInterval-1)){
case (_,lastDate) =>
val nextDate = lastDate plusDays dayInterval
(lastDate plusDays 1, if (nextDate isAfter endDate) endDate
else nextDate)
}.takeWhile(_._1 isBefore endDate)
println(intervals.mkString("\n"))
}
用法:
generateDates(LocalDate.parse("2018-01-01"), LocalDate.parse("2018-02-20"), 20)
// (2018-01-01,2018-01-20)
// (2018-01-21,2018-02-09)
// (2018-02-10,2018-02-20)
要明确的是,只有最后一部分(0到段)
真正涉及功能性的东西;这就是说,@Terry的答案是一种核心的功能性方法。要清楚,只有最后一部分(0到片段)
真正涉及功能性东西;这就是说,@Terry的回答是一种核心功能性的方法,我理解你的方法,但我想在地图中保留开始和结束日期(间隔计算后),以便进一步处理。可能吗?我已经编辑了上面的代码。映射可能不是数据结构的最佳选择,因为它不是有序的。我的代码返回一个简单而完美的列表[(LocalDate,LocalDate,Int)]。我理解您的方法,但我希望在映射中保留开始和结束日期(在间隔计算之后),以便进一步处理。可能吗?我已经编辑了上面的代码。映射可能不是数据结构的最佳选择,因为它不是有序的。我的代码返回一个简单而完美的列表[(LocalDate,LocalDate,Int)]。也接受你的答案。也接受你的答案。如果我们的间隔小于?“我想保持星号和结束日期不变。”威廉姆,我不确定我是否理解。你能举个例子吗?如果我的开始和结束日期少于我的间隔时间,我什么都不需要做。只需返回原始值作为开始和结束日期。@WilliamR,请查看编辑后的答案。这个想法仍然是一样的。我只是稍微改变了开始累加器的值来处理拐角的情况。如果我们的间隔小于?“我想保持星号和结束日期不变。”威廉姆,我不确定我是否理解。你能举个例子吗?如果我的开始和结束日期少于我的间隔时间,我什么都不需要做。只需返回原始值作为开始和结束日期。@WilliamR,请查看编辑后的答案。这个想法仍然是一样的。我只是稍微改变了开始累加器的值,以处理拐角的情况。