Последовательные дни отображаются из массива строк, разделенных запятыми. - PullRequest
2 голосов
/ 12 октября 2019

В качестве входных данных я получил несколько строковых целых чисел, разделенных запятыми, например, следующие строки:

  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" приведет к следующему результату: воскресенье , понедельник , среда до пятница .

Ответы [ 2 ]

1 голос
/ 15 октября 2019

Если вы можете, я просто придерживаюсь заданного API времени (например, java.time, если вы используете Java 8 или joda-time и т. Д.). Следующее решение также будет работать с вашим enum, но вам нужно немного его адаптировать (т. Е. DayOfWeek имеет getDisplayName, а также позволяет добавлять отдельные дни и всегда получать следующий день подряд).

Я разделил работу на 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
    
1 голос
/ 12 октября 2019
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)
    }
}

пример вывода:

с воскресенья по вторник, с четверга по субботу

с пятницы по воскресенье

с понедельника по четверг

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...