从逗号分隔的整数的字符串数组映射的连续天数



我收到了多个逗号分隔的字符串整数作为输入,例如以下字符串:

  1. "5,6,0"
  2. "0,1,2">
  3. "1,2,3,4">

这些整数中的每一个都表示一周中的某一天

  • 0 = 星期日 1 = 星期一 2 = 星期二 3 = 星期三 4 = 星期四 5 = 星期五 6 = 星期六

在第一个字符串的情况下,这意味着周四周日第二个字符串在星期日星期二有效 第三个字符串在星期一星期四有效

目前,我正在使用以下内容

private fun mapOfDays(validDays: String): LinkedHashMap<Int, String>
{
if (!validDays.isBlank())
{
val daysArray = validDays.split("\s*,\s*") as Array<String>
var mapDays = LinkedHashMap<Int, String>()
var mapDay = LinkedHashMap<Int, String>()
mapDays[0] = "SUNDAY"
mapDays[1] = "MONDAY"
mapDays[2] = "TUESDAY"
mapDays[3] = "WEDNESDAY"
mapDays[4] = "THURSDAY"
mapDays[5] = "FRIDAY"
mapDays[6] = "SATURDAY"
for (day in daysArray)
{
if (mapDays.containsKey(day.toInt()))
{
mapDay[day.toInt()] = mapDays[day.toInt()]!!
}
}
return mapDay
}
return LinkedHashMap()
}
private fun mappedDays(mapOfDays: LinkedHashMap<Int, String>?): String
{
if (!mapOfDays.isNullOrEmpty())
{
val mapSize = mapOfDays.size
if (mapSize > 6) return "All Day"
if (mapSize > 5) return sixDayString(mapOfDays)
if (mapSize > 4) return fiveDayString(mapOfDays)
if (mapSize > 3) return fourDayString(mapOfDays)
if (mapSize > 2) return threeDayString(mapOfDays)
if (mapSize > 1) return twoDayString(mapOfDays)
if (mapSize > 0) return oneDayString(mapOfDays)
}
return ""
}
private fun twoDayString(mapOfDays: LinkedHashMap<Int, String>): String
{
val firstPosition: Int = mapOfDays.keys.toIntArray()[0]
val lastPosition: Int = mapOfDays.keys.toIntArray()[1]
val lastDay = Days.values()[lastPosition]
val firstDay = Days.values()[firstPosition]
return "$firstDay and $lastDay"
}
private fun oneDayString(mapOfDays: LinkedHashMap<Int, String>): String
{
var firstPosition: Int = mapOfDays.keys.toIntArray()[0]
val firstDay = Days.values()[firstPosition]
return "$firstDay"
}
private fun threeDayString(mapOfDays: LinkedHashMap<Int, String>): String
{
val firstPosition: Int = mapOfDays.keys.toIntArray()[0]
val secondPosition: Int = mapOfDays.keys.toIntArray()[1]
val thirdPosition: Int = mapOfDays.keys.toIntArray()[2]
val firstDay = Days.values()[firstPosition]
val secondDay = Days.values()[secondPosition]
val lastDay = Days.values()[thirdPosition]
return "$firstDay, $secondDay and $lastDay"
}
private fun fourDayString(mapOfDays: LinkedHashMap<Int, String>): String
{
val firstPosition: Int = mapOfDays.keys.toIntArray()[0]
val secondPosition: Int = mapOfDays.keys.toIntArray()[1]
val thirdPosition: Int = mapOfDays.keys.toIntArray()[2]
val fourthPosition: Int = mapOfDays.keys.toIntArray()[3]
val firstDay = Days.values()[firstPosition]
val secondDay = Days.values()[secondPosition]
val thirdDay = Days.values()[thirdPosition]
val lastDay = Days.values()[fourthPosition]
return "$firstDay, $secondDay, $thirdDay and $lastDay"
}
private fun fiveDayString(mapOfDays: LinkedHashMap<Int, String>): String
{
val firstPosition: Int = mapOfDays.keys.toIntArray()[0]
val secondPosition: Int = mapOfDays.keys.toIntArray()[1]
val thirdPosition: Int = mapOfDays.keys.toIntArray()[2]
val fourthPosition: Int = mapOfDays.keys.toIntArray()[3]
val fifthPosition: Int = mapOfDays.keys.toIntArray()[4]
val firstDay = Days.values()[firstPosition]
val secondDay = Days.values()[secondPosition]
val thirdDay = Days.values()[thirdPosition]
val fourthDay = Days.values()[fourthPosition]
val lastDay = Days.values()[fifthPosition]
return "$firstDay, $secondDay, $thirdDay, $fourthDay and $lastDay"
}
private fun sixDayString(mapOfDays: LinkedHashMap<Int, String>): String
{
var firstPosition: Int = mapOfDays.keys.toIntArray()[0]
var lastPosition: Int = 0
for (day in mapOfDays.keys)
{
lastPosition = day
}
val lastDay = Days.values()[lastPosition]
val firstDay = Days.values()[firstPosition]
return "$firstDay to $lastDay"
}
}
enum class Days()
{
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}

但是,我当前的实现能够告诉我包括哪些天,并且无法绘制出天数组,例如:

如果我得到"0,1,3,4,5,6" 我想要的最终字符串输出如下:周三周一

"0,1,3,4,5"将导致以下结果:星期日星期一星期三星期五

package days
import java.lang.IllegalArgumentException

class DaysFactory {
fun dayFromInt(index: Int): Day {
return when (index) {
0 -> Day.Sunday
1 -> Day.Monday
2 -> Day.Tuesday
3 -> Day.Wednesday
4 -> Day.Thursday
5 -> Day.Friday
6 -> Day.Saturday
else -> throw IllegalArgumentException("illigal index :$index")
}
}
enum class Day(val index: Int) {
Sunday(0), Monday(1), Tuesday(2), Wednesday(3), Thursday(4), Friday(5), Saturday(6)
}
}

class DaysRange(val seed: String) {
var stringFormat = ""
private fun getTomorrow(dayIndex: Int): Int {
if (dayIndex != 6) return dayIndex + 1
return 0
}
override fun toString(): String =stringFormat

init {
if (isValidInput(seed)) {
val dayFactory = DaysFactory()
val indexes = seed.split(",").map { it.toInt() }
val days = indexes.map { dayFactory.dayFromInt(it) }
val ranges = splitIndexesToRanges(indexes)
ranges.forEach { range ->
if (range.size > 2) {
stringFormat += "${dayFactory.dayFromInt(range.first())} to ${dayFactory.dayFromInt(range.last())},"
} else
range.forEach {
stringFormat += "${dayFactory.dayFromInt(it)},"
}
}
stringFormat = stringFormat.dropLast(1)
}
}
private fun splitIndexesToRanges(daysRange: List<Int>): ArrayList<List<Int>> {
val result = ArrayList<List<Int>>()
val slicePoint = ArrayList<Int>()
for (i in 0 until daysRange.size - 1) {
if (getTomorrow(daysRange[i]) != daysRange[i + 1]) {
slicePoint.add(i)
}
}
var start = 0
slicePoint.forEach {
result.add(daysRange.slice(start..it))
start = it + 1
}
result.add(daysRange.slice(start until daysRange.size))
return result
}
}
private fun isValidInput(seed: String): Boolean = true

fun main(args: Array<String>) {
val input = listOf(
"0,1,2,4,5,6",
"5,6,0",
"1,2,3,4"
)
input.forEach {
val dr = DaysRange(it)
println(dr)
}
}

示例输出:

周日至周二,周四至周六

周五至周日

周一至周四

如果可以的话,我会坚持使用给定的时间 API(例如java.time如果你使用的是Java 8或joda-time等(。以下解决方案也适用于您的enum,但您需要对其进行一些调整(即DayOfWeekgetDisplayName,还允许添加单天并始终获得下一个连续的一天(。

我将工作分为 3 个单独的任务。

  1. 将输入读入DayOfWeek列表:

    fun readInput(input : String) : List<DayOfWeek> = input.splitToSequence(",")
    .map(String::toInt)
    .map {
    /* your 0 is Sunday which is 7 for DayOfWeek; rest is the same */
    if (it == 0) 7 else it
    }
    .map(DayOfWeek::of)
    .toList()
    

    也许您想向其添加.distinct().sorted()或想要事先验证输入......这取决于您真正想要确保的内容...

  2. 将星期几转换为连续天数的列表:

    fun List<DayOfWeek>.toDayRangeList() : List<DayRange> = fold(mutableListOf<DayRange>()) { consecutiveDaysList, day ->
    consecutiveDaysList.apply {
    lastOrNull()?.takeIf { it.to + 1 == day }?.apply {
    to = day
    } ?: add(DayRange(day))
    }
    }
    

    为此,我还引入了一个DateRange类,以便轻松更改结束日期......您也可以使用不可变对象执行此操作,但我发现这种方式更容易。该DateRange还包括一些帮助程序方法,可以轻松地以您想要的形式获取实际日期(在我的示例中FULL_STANDALONE(:

    data class DayRange(var from: DayOfWeek, var to: DayOfWeek = from) {
    private fun DayOfWeek.toFullString(locale : Locale) = getDisplayName(TextStyle.FULL_STANDALONE, locale)
    fun toString(locale : Locale) : String = when (from) {
    // TODO add missing locale specific strings!
    to -> from.toFullString(locale)
    to + 1 -> "All day"
    else -> "${from.toFullString(locale)} to ${to.toFullString(locale)}"
    }
    // just for convenience we use our custom toString-function:
    override fun toString() = toString(Locale.getDefault())
    }
    
  3. 可选地"展平"列表,即如果最后一天和第一天是连续的,则将它们合并到一个范围中。由于我们直接处理DayOfWeek我们可以简单地添加另一天并比较两天,无论一天是否是一周的最后一天:

    fun List<DayRange>.flatten(): List<DayRange> {
    if (size > 1) {
    val first = first()
    val last = last()
    if (last.to + 1 == first.from)
    return dropLast(1).drop(1)
    .toMutableList()
    .apply {
    add(DayRange(last.from, first.to))
    }
    }
    return this
    }
    
  4. 将它们放在一起/演示:

    listOf("1", "1,2", "1,0", "1,2,3", "1,2,4,5", "1,2,4,5,0", "1,2,3,4,5,6,0", "2,3,4,5,6,0,1")
    .forEach { input ->
    print(input)
    readInput(input)
    .toDayRangeList()
    .flatten()
    .joinToString(", ")
    .also {
    println("-> $it")
    }
    }
    

    其中打印以下内容:

    1 -> Monday
    1,2 -> Monday to Tuesday
    1,0 -> Sunday to Monday
    1,2,3 -> Monday to Wednesday
    1,2,4,5 -> Monday to Tuesday, Thursday to Friday
    1,2,4,5,0 -> Thursday to Friday, Sunday to Tuesday
    1,2,3,4,5,6,0 -> All day
    2,3,4,5,6,0,1 -> All day
    

最新更新