ArrayList удалить, если уже содержит строку, начинающуюся с `it` в Kotlin

#kotlin #arraylist

#kotlin #arraylist

Вопрос:

У меня есть ArrayList<String> таких данных:

 download
download name:string
download name:string url:string
download test:string
list
print
print name:string
reload
reload name:string
  

Пример вывода должен выглядеть следующим образом:

 download name:string url:string
download test:string // note this one does not get filtered
list
print name:string
reload name:string
  

Но я хотел бы удалить, download поскольку download name:string существует, а также удалить, download name:string поскольку download name:string url:string существует.

Я попытался использовать два списка массивов и кучу фильтров, но это стало чрезвычайно запутанным, и решения, которые я придумал, привели к пустому списку массивов.

Пример, который я пробовал:

                 val subCommands1 = arrayListOf<String>()

                subCommands
                    .stream()
                    .sorted(Comparator.comparingInt(String::length))
                    .filter {
                        var found = false
                        subCommands1
                            .stream()
                            .sorted(Comparator.comparingInt(String::length))
                            .collect(Collectors.toList())
                            .reversed()
                            .forEach { comIt ->
                                if (comIt.startsWith(it)) {
                                    found = true
                                }
                            }
                        if (!found) {
                            subCommands1.add(it)
                        }
                        !found
                    }
                    .collect(Collectors.toList())
  

Любые альтернативы тому, что я делаю, были бы оценены.

Комментарии:

1. Я не совсем понимаю определение вашей проблемы, но причина, по которой вы получаете пустой список, заключается в том, что вы фильтруете subCommands список с самим собой, что означает, что каждый элемент будет найден (найдено == true). Когда вы отменяете условие, все элементы снова найдены (найдено == true), но вы не фильтруете какие-либо элементы (!найдено == false), что приводит к получению исходного списка.

2. Вы были правы, я попробовал это , и теперь это дает мне это , что тоже не очень хорошо

Ответ №1:

 fun filterSubCommands(list: List<String>): List<String> {
    if (list.size < 2) return ArrayList(list)
    val result = ArrayList<String>()
    list.asSequence().sorted().zipWithNext().forEach { (a, b) ->
        if (!b.startsWith(a)) result.add(a)
    }
    result.add(list.last())
    return result
}
  

Ответ №2:

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

 fun main(): Unit {
    val filteredCommands = HashSet<String>()
    commands
        .sortedByDescending { it.length }
        .forEach { command ->
            if (filteredCommands.find { it.startsWith(command) } == null) {
                filteredCommands.add(command)
            }
        }
    println(filteredCommands.toList().joinToString())
}
  

Вы можете запустить ее на этой игровой площадке.

Это может не сработать в зависимости от ваших командных правил, которые я не совсем понимаю, но это работает правильно для данного ввода.

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

 fun main(): Unit {
    val filteredCommands = commands
        .sortedByDescending { it.length }
        .fold(emptySet<String>()) { filtered, command ->
            if (filtered.find { it.startsWith(command) } == null) 
                filtered   command 
            else 
                filtered
        }
    println(filteredCommands.toList().joinToString())
}
  

Вот игровая площадка с примером.