【问题标题】:Kotlin Filtering a list of Objects to make sure at least 1 Workstation is coveredKotlin 过滤对象列表以确​​保至少覆盖 1 个工作站
【发布时间】:2022-09-25 19:09:54
【问题描述】:

在 Kotlin 中,我需要确保覆盖所有工作站,以便人们可以预订休假,有 4 个工作站,但人们一次只能做 1 个。我需要确保所有工作站至少有 1 人参与,我的代码存在的问题是人们能够使用多个工作站

enum class WorkStations {
    PANEL, OUTSIDE, MOVEMENTS, EXTRUDER
}

data class Operator(val name: String, val workStations: List<WorkStations> = 
emptyList())

fun main() {

val array = arrayListOf(
    Operator(
        \"Andy\",
        listOf(WorkStations.PANEL, WorkStations.OUTSIDE, WorkStations.MOVEMENTS)
    ),
    Operator(
        \"Alan\",
        listOf(WorkStations.PANEL, WorkStations.OUTSIDE, WorkStations.MOVEMENTS)
    ),
    Operator(
        \"Matt\",
        listOf(WorkStations.OUTSIDE)
    ),
    Operator(
        \"Paul\",
        listOf(WorkStations.EXTRUDER, WorkStations.MOVEMENTS)
    ),
    Operator(
        \"Jack\",
        listOf(WorkStations.EXTRUDER, WorkStations.MOVEMENTS)
    ),
    Operator(
        \"James\",
        listOf(WorkStations.OUTSIDE)
    ),
    Operator(
        \"Tall Paul\",
    ),
    Operator(
        \"Josh\")
    )

fun areWorkStationsCovered(array: ArrayList<Operator>): Boolean {
    val newList = array.flatMap { it.workStations }.groupingBy { it }.eachCount().filter { it.value >= 1 }
    println(newList)
    return newList.size >= 4
}

println(areWorkStationsCovered(array))

}

返回:

{PANEL=2, OUTSIDE=4, MOVEMENTS=4, EXTRUDER=2}
true

但这是不正确的,好像 Paul 和 Alan 都关闭了,然后返回:

{PANEL=1, OUTSIDE=3, MOVEMENTS=2, EXTRUDER=1}
true

看起来不错,但不正确,因为 Jack 需要做 EXTRUDER,因此只有 1 个动作人员,而 Andy 必须做 PANEL,因此没有动作人员,我想我需要从原始列表中删除人员,但就是想不出一个简单,实用的方法任何想法将不胜感激......

  • 我不明白为什么它不正确。你期望什么输出?请不要描述它。像这样发布:{PANEL=1, ... }
  • P1 可以做 A, B, C, P2 可以做 A, B, C, P3 可以做 B, P4 可以做 C, D, P5 可以做 C, D, P6 可以做 B. 各一个 (A, B, C、D) 都是必需的,但 P\'s 一次只能做 1 个,即如果 P2 被删除,P1 必须是 A ONLY。
  • 我有问题。我给你写了一个答案,但很抱歉没有代码。但是算法应该很清楚。如果我有时间,我会编辑我的答案并添加一些代码
  • 欣赏库兹杜
  • 我编辑我的答案并添加一些工作代码。我希望这有帮助

标签: kotlin


【解决方案1】:

如果我正确理解问题,每个操作员可能只执行一个工作站,并且每个工作站必须至少占用一次。

当然,有更好、更高效的解决方案。但你总是可以优化到最后。

我写了测试,到目前为止这应该有效。我不得不稍微改变你的数据结构和你的测试数据。

enum class WorkStation {
    PANEL, OUTSIDE, MOVEMENTS, EXTRUDER
}

data class Operator(
    val name: String, var workStations: MutableList<WorkStation> =
        mutableListOf()
)

data class OperatorWithWorkstation(
    val name: String, var workStation: WorkStation
)

class ExampleUnitTest {

    private val operators = arrayListOf(
        Operator(
            "Andy",
            mutableListOf(WorkStation.MOVEMENTS, WorkStation.PANEL, WorkStation.EXTRUDER)
        ),
        Operator(
            "Alan",
            mutableListOf(WorkStation.MOVEMENTS, WorkStation.OUTSIDE, WorkStation.EXTRUDER)
        ),
        Operator(
            "Matt",
            mutableListOf(WorkStation.EXTRUDER)
        ),
        Operator(
            "Paul",
            mutableListOf(WorkStation.EXTRUDER, WorkStation.MOVEMENTS)
        ),
        Operator(
            "Jack",
            mutableListOf(WorkStation.EXTRUDER, WorkStation.MOVEMENTS)
        ),
        Operator(
            "James",
            mutableListOf(WorkStation.OUTSIDE)
        ),
        Operator(
            "Tall Paul",
        ),
        Operator(
            "Josh"
        )
    )

    private val operatorsOnWorkstation = mutableListOf<OperatorWithWorkstation>()

    @Test
    fun everyWorkSpaceIsManned() {
        // WHEN
        addOperatorsToWorkstations(1)

        // THEN
        val allWorkstations = operatorsOnWorkstation.map { it.workStation }
        assertTrue(allWorkstations.count() == 4)
        assertTrue(allWorkstations.contains(WorkStation.EXTRUDER))
        assertTrue(allWorkstations.contains(WorkStation.OUTSIDE))
        assertTrue(allWorkstations.contains(WorkStation.MOVEMENTS))
        assertTrue(allWorkstations.contains(WorkStation.PANEL))
    }

    @Test
    fun notEveryWorkSpaceIsManned() {
        // GIVEN

        // remove ANDY
        operators.removeAt(0)
        // remove ALAN
        operators.removeAt(0)

        // WHEN
        addOperatorsToWorkstations(1)

        // THEN
        val allWorkstations = operatorsOnWorkstation.map { it.workStation }
        assertTrue(allWorkstations.count() == 3)
    }

    @Test
    fun checkIfAlgorithmPicksTheWorkstationClever() {
        // GIVEN
        // remove PAUL
        operators.removeAt(3)
        // remove JACK
        operators.removeAt(3)

        // WHEN
        addOperatorsToWorkstations(1)

        // THEN
        val allWorkstations = operatorsOnWorkstation.map { it.workStation }
        assertTrue(allWorkstations.count() == 4)
        assertTrue(allWorkstations.contains(WorkStation.EXTRUDER))
        assertTrue(allWorkstations.contains(WorkStation.OUTSIDE))
        assertTrue(allWorkstations.contains(WorkStation.MOVEMENTS))
        assertTrue(allWorkstations.contains(WorkStation.PANEL))
    }

    private fun addOperatorsToWorkstations(startCount: Int) {
        if (startCount > 4 || operators.isEmpty()) {
            return
        }

        val operator = findOperatorForWorkStation(startCount)

        if (operator == null) {
            addOperatorsToWorkstations(startCount + 1)
            return
        }

        operators.removeIf { it.name == operator.name }
        operatorsOnWorkstation.add(operator)
        addOperatorsToWorkstations(startCount)
    }

    private fun findOperatorForWorkStation(count: Int): OperatorWithWorkstation? {
        // start with operators which can work on less workstations
        val filteredOperators = operators.filter { it.workStations.count() == count }

        var result: OperatorWithWorkstation? = null
        val allMannedWorkstations = operatorsOnWorkstation.map { it.workStation }

        for (operator in filteredOperators) {
            // remove all workstations which already in use
            for (workstation in allMannedWorkstations) {
                operator.workStations.remove(workstation)
            }

            if (operator.workStations.isNotEmpty()) {


                // has this operator a workstations which only can solved by him
                val allPossibleWorkstations = operators.filter { it.workStations.count() >= count }
                    .flatMap { it.workStations }.distinct()

                var selectedWorkStation: WorkStation? = null
                for (workstation in operator.workStations) {
                    if (!allPossibleWorkstations.contains(workstation)) {
                        selectedWorkStation = workstation
                    }
                }

                if (selectedWorkStation == null) {
                    selectedWorkStation = operator.workStations.first()
                }

                // only the workstation where the operator is working on is added
                result = OperatorWithWorkstation(
                    name = operator.name,
                    workStation = selectedWorkStation
                )
                break
            }
        }
        return result
    }
}

这个想法是你用一个有一个工作站的操作员填充一个数组。

我知道你可以优化很多。我认为 Big O Annotation 是 n^2 但你必须决定你想优化多少。我使用 for 循环进行列表算术并删除。我认为intersectsubtract 也有可能的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-23
    • 2019-07-10
    • 1970-01-01
    • 2020-06-24
    • 1970-01-01
    • 2017-05-10
    • 1970-01-01
    相关资源
    最近更新 更多