По сути, у вас есть проблема поиска.
Я немного изменил вашу реализацию, чтобы сделать ее более точной для справки:
fun isEqual(listA: List<ListAelement>, listB: List<ListBelement>): List<ListCelement> {
val listC: MutableList<ListCelement> = mutableListOf()
// you don't need a while loop or a counter variable as you need to look at every item in list A
listA.forEach { listAItem ->
var found = false
// search for each item in list A in list B
// this is a linear search
listB.forEach { listBItem ->
if (listBItem.id == listAItem.id) {
// println("matched item $it")
found = true // cache the result that it has been found rather than printing out
}
}
// create your list C with the ListCelement instance that holds the result of whether it was found in List B or not
listC.add(
ListCelement(id=listAItem.id, isElementInA=found)
)
}
return listC
}
Текущая реализация имеет временную сложность = O (N * M) (где N и M - размеры списков A и B), потому что для каждого элемента в списке A вы должны перебирать список B при выполнении линейного поиска для него.
Это можно оптимизировать с помощью бинарного поиска . Однако двоичный поиск требует сортировки пространства поиска. В вашем случае список B, являющийся пространством поиска, должен быть отсортирован по полю id, так как вы определяете элементы списка A, которые находятся в списке B.
Он имеет временную сложность = O (log N) (где N - размер области поиска), потому что вы используете порядок в пространстве поиска, чтобы отбрасывать половину элементов при каждой попытке, пока вы не найдете свой элемент поиска или не уменьшите пространство поиска к одному элементу, который не является вашим элементом поиска, и в этом случае вы выходите из поиска.
Ниже представлена реализация с использованием двоичного поиска:
/**
* We declare a package-level function main which returns Unit and takes
* an Array of strings as a parameter. Note that semicolons are optional.
*/
data class ListAelement(
val fieldA: Double = 2.0,
// this is the field that i have to check with listB
val id: String,
val someField: String,
val someOtherField: String
)
data class ListBelement(
// list b only has id
val id: String
)
data class ListCelement(
val fieldA: Double = 2.0,
val id: String,
val someField: String,
val someOtherField: String,
// this should be true if it is in ListB
val isElementInA: Boolean
)
fun isEqual(listA: List<ListAelement>, listB: List<ListBelement>): List<ListCelement> {
val sortedListB = listB.sortedWith(compareBy({ it.id }))
val listC: MutableList<ListCelement> = mutableListOf()
listA.forEach { listAItem ->
listC.add(
ListCelement(
id=listAItem.id,
someField=listAItem.someField,
someOtherField=listAItem.someOtherField,
isElementInA=binarySearchListB(sortedListB, listAItem) // linear search replaced with this binary search
)
)
}
return listC
}
// the kotlin collections package ships with a binarySearch() function https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/binary-search.html
// I have opted to implement a custom one so that I can have a Boolean return type
fun binarySearchListB(searchSpace:List<ListBelement>, searchItem: ListAelement, leftIndex:Int = 0, rightIndex: Int = searchSpace.size - 1): Boolean {
val midIndex: Int = (leftIndex + rightIndex) / 2
val midItem: ListBelement = searchSpace[midIndex]
// exit condition if item does not exist
if (leftIndex == rightIndex && searchItem.id != searchSpace[leftIndex].id) {
return false
}
if (midItem.id == searchItem.id) {
// found
return true
} else if(searchItem.id < midItem.id) {
// go to the left
return binarySearchListB(searchSpace, searchItem, leftIndex, midIndex - 1)
} else if(searchItem.id > midItem.id) {
// go to the right
return binarySearchListB(searchSpace, searchItem, midIndex + 1, rightIndex)
}
return false
}
fun main(args: Array<String>) {
val listA = listOf<ListAelement>(
ListAelement(1.2, "12345", "someField", "someOtherField"),
ListAelement(1.2, "12343", "someField", "someOtherField"),
ListAelement(1.2, "1234566", "someField", "someOtherField"),
ListAelement(1.2, "11233", "someField", "someOtherField")
)
val listB = listOf<ListBelement>(ListBelement("1234566"), ListBelement("12345"), ListBelement("123123"))
// new list
val listC = isEqual(listA, listB)
println(listC)
}
Вот результат:
[ListCelement(fieldA=2.0, id=12345, someField=someField, someOtherField=someOtherField, isElementInA=true), ListCelement(fieldA=2.0, id=12343, someField=someField, someOtherField=someOtherField, isElementInA=false), ListCelement(fieldA=2.0, id=1234566, someField=someField, someOtherField=someOtherField, isElementInA=true), ListCelement(fieldA=2.0, id=11233, someField=someField, someOtherField=someOtherField, isElementInA=false)]
ОБНОВЛЕНИЕ:
Вот обновление, которое преобразует список B в HashSet строк, содержащих идентификаторы ListBelement, чтобы получить поиск с постоянным временем (т.е. O (1) ), как предложено в комментариях:
/**
* We declare a package-level function main which returns Unit and takes
* an Array of strings as a parameter. Note that semicolons are optional.
*/
data class ListAelement(
val fieldA: Double = 2.0,
// this is the field that i have to check with listB
val id: String,
val someField: String,
val someOtherField: String
)
data class ListBelement(
// list b only has id
val id: String
)
data class ListCelement(
val fieldA: Double = 2.0,
val id: String,
val someField: String,
val someOtherField: String,
// this should be true if it is in ListB
val isElementInA: Boolean
)
fun isEqual(listA: List<ListAelement>, listB: List<ListBelement>): List<ListCelement> {
// construct a HashSet of string ids from listB
// there could be a more idiomatic way to do it
// more about HashSet here -> https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-hash-set/
val listBHashSet: HashSet<String> = hashSetOf()
listB.forEach { listBItem ->
listBHashSet.add(listBItem.id)
}
val listC: MutableList<ListCelement> = mutableListOf()
listA.forEach { listAItem ->
listC.add(
ListCelement(
id=listAItem.id,
someField=listAItem.someField,
someOtherField=listAItem.someOtherField,
isElementInA=listBHashSet.contains(listAItem.id) // linear search replaced with this hashset lookup search
)
)
}
return listC
}
fun main(args: Array<String>) {
val listA = listOf<ListAelement>(
ListAelement(1.2, "12345", "someField", "someOtherField"),
ListAelement(1.2, "12343", "someField", "someOtherField"),
ListAelement(1.2, "1234566", "someField", "someOtherField"),
ListAelement(1.2, "11233", "someField", "someOtherField")
)
val listB = listOf<ListBelement>(ListBelement("1234566"), ListBelement("12345"), ListBelement("123123"))
// new list
val listC = isEqual(listA, listB)
println(listC)
}
Вывод:
[ListCelement(fieldA=2.0, id=12345, someField=someField, someOtherField=someOtherField, isElementInA=true), ListCelement(fieldA=2.0, id=12343, someField=someField, someOtherField=someOtherField, isElementInA=false), ListCelement(fieldA=2.0, id=1234566, someField=someField, someOtherField=someOtherField, isElementInA=true), ListCelement(fieldA=2.0, id=11233, someField=someField, someOtherField=someOtherField, isElementInA=false)]