How to remove element from iterator if condition depends on property of the object the iterator is based on? - kotlin

Let me elaborate:
I need to be able to iterate over a list of objects. Each of the objects has a property which is a list, and I have to check if that list contains any elements that are not in another list.
When I tried to do it by using nested for loops, it kept giving me concurrent modification exceptions, so I tried to use an iterator, but now I'm stuck, since if I make an iterator based on the list of objects, I can't access the individual object's properties to then iterate over.
Here's some example code of what I was trying to accomplish:
for (preference in preferencesWithRestaurant) {
for (restaurantID in preference.restaurantIDs) {
// One method I tried using
preferencesWithRestaurant.removeIf{ !listOfIds.contains(restaurantID) }
/* alternate method I tried using
if (!listOfIds.contains(restaurantID)) {
preferencesWithRestaurant.remove(preference)
}
*/
}
}

If you can replace the value of preferencesWithRestaurant or store the result in another variable then you can filter it:
preferencesWithRestaurant = preferencesWithRestaurant.filter { preference ->
preference.restaurantIDs.all { it in listOfIds }
}
Depending on the exact type of preferencesWithRestaurant you may need to convert it to the proper type, e.g. invoke toMutableList() at the end.
If you prefer to modify preferencesWithRestaurant in-place, then you can use retainAll() (thanks #Tenfour04):
preferencesWithRestaurant.retainAll { preference ->
preference.restaurantIDs.all { it in listOfIds }
}
Alternatively, you can keep your original approach, but use a mutable iterator to remove an item while iterating:
val iter = preferencesWithRestaurant.listIterator()
for (preference in iter) {
for (restaurantID in preference.restaurantIDs) {
if (!listOfIds.contains(restaurantID)) {
iter.remove()
break
}
}
}

Related

MutableList of MutableLists in Kotlin: adding element error

Why I'm getting "java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0" while running next code??? :
val totalList = mutableListOf<MutableList<Int>>()
fun main() {
for (i in 0..15) {
for (j in 0..10) {
*some operations and calculations with **var element of type Int***
totalList[i].add(element)
}
}
}
I was thinking that in such case while iterating through 'j' it should add elements to mutableList[i], after this it should start adding elements to mutableList[i + 1] etc.... But instead I am recieving IndexOutOfBoundsException....
val totalList = mutableListOf<MutableList<Int>>()
All this does is create one list which is going to contain MutableList<Int> items. Right now, there's nothing in it (you've supplied no initial elements in the parentheses).
Skip forward a bit, and you do this:
totalList[0].add(element)
You're trying to get the first element of that empty list and add to it. But there is no first element (index 0) because the list is empty (length 0). That's what the error is telling you.
There's lots of ways to handle this - one thing you could do is create your lists up-front:
// create the 16 list items you want to access in the loop
// (the number is the item count, the lambda generates each item)
val totalList = MutableList(16) { mutableListOf<Int>() }
// then refer to that list's properties in your loop (no hardcoded 0..15)
for (i in totalList.indices) {
...
// guaranteed to exist since i is generated from the list's indices
totalList[i].add(element)
}
Or you could do it the way you are now, only using getOrElse to generate the empty list on-demand, when you try to get it but it doesn't exist:
for (i in 0..15) {
for (j in 0..10) {
// if the element at i doesn't exist, create a list instead, but also
// add it to the main list (see below)
totalList.getOrElse(i) {
mutableListOf<Int>().also { totalList.add(it) }
}.add(element)
}
}
Personally I don't really like this, you're using explicit indices but you're adding new list items to the end of the main list. That implicity requires that you're iterating over the list items in order - which you are here, but there's nothing enforcing that. If the order ever changed, it would break.
I'd prefer the first approach - create your structure of lists in advance, then iterate over those and fill them as necessary. Or you might want to consider arrays instead, since you have a fixed collection size you're "completing" by adding items to specific indices
Another approach (that I mentioned in the comments) is to create each list as a whole, complete thing, and then add that to your main list. This is generally how you do things in Kotlin - the standard library contains a lot of functional tools to allow you to chain operations together, transform things, and create immutable collections (which are safer and more explicit about whether they're meant to be changed or they're a fixed set of data).
for (i in 0..15) {
// map transforms each element of the range (each number) to an item,
// resulting in a list of items
val items = (0..10).map { j ->
// do whatever you're doing
// the last expression in the lambda is its resulting value,
// i.e. the item that ends up in the list
element
}
// now you have a complete list of items, add them to totalList
totalList.add(items)
}
(Or you could create the list directly with List(11) { j -> ... } but this is a more general example of transforming a bunch of things to a bunch of other things)
That example there is kinda half and half - you still have the imperative for loop going on as well. Writing it all using the same approach, you can get:
val totalList = (0..15).map { i ->
(0..10).map { j ->
// do stuff
element
}
}
I'd probably prefer the List(count) { i -> ... } approach for this, it's a better fit (this is a general example). That would also be better since you could use MutableList instead of List, if you really need them to be mutable (with the maps you could just chain .toMutableList() after the mapping function, as another step in the chain). Generally in Kotlin, collections are immutable by default, and this kind of approach is how you build them up without having to create a mutable list etc. and add items to it yourself

How figure out multiple nested if else condition?

I am not getting an efficient way to check below mentioned condition.
What I want to achieve is that-
There are some processes that need to be done if their corresponding boolean is true suggesting to start the process. So I want to check if a particular condition is done only if it should be started.
There are some boolean variables
var shouldStartProcessA
var shouldStartProcessB
var shouldStartProcessC
var isADone
var isBDone
var isCDone
if (shouldStartProcessA && shouldStartProcessB && shouldStartC) {
if (isADone && isBDone && isCDone) {
// Every process completed
}
}
if (shouldStartProcessA && shouldStartProcessB) {
if (isADone && isBDone) {
// Every process completed
}
}
if (shouldStartProcessA && shouldStartC) {
if (isADone && isCDone) {
// Every process completed
}
}
if (shouldStartProcessB && shouldStartC) {
if (isBDone && isCDone) {
// Every process completed
}
}
if (shouldStartProcessA) {
if (isADone) {
// Every process completed
}
}
if (shouldStartProcessB) {
if (isBDone) {
// Every process completed
}
}
if (shouldStartProcessC) {
if (isCDone) {
// Every process completed
}
}
This type of validating condition grows exponentially by introducing every other boolean. I am struggling to find a straightforward implementation to check these conditions.
Instead of doing things this way, I'd recommend a data structure that allows you to add tasks and check their state. There are a lot of ways to do that, but the basic idea is you can iterate over all the items and use functions like all to confirm they're all in the appropriate state. That way you don't have to hand-wire everything together
You could use a Map and add tasks to it, initially mapping them to false and setting that to true when they're completed. Or create a Set and add your tasks to that (I'm assuming you want one of each at most), and remove them / move them to a "done" list when they complete. That kind of idea. You could create an enum class to represent your tasks if you want, so each one is its own instance (e.g. Process.A, like having a dedicated, fixed variable) and you can easily use those in your logic
If you really want variables for each process, instead of a data structure, I'd still recommend rolling each pair into a single state, something like this:
enum class State {
UNUSED, PENDING, DONE
}
var processA = State.UNUSED
var processB = State.PENDING
// etc
// you can easily check them like this:
// create a list of all the variables you want to check - we're using references
// to the properties themselves (with the ::), not the current value!
val allProcesses = listOf(::processA, ::processB)
// now you have that collection, you can easily iterate over them all
// and work out what's what - we need to use get() to get the current values
val allFinished = allProcesses
.filterNot { it.get() == State.UNUSED } // ignore unused processes
.all { it.get() == State.DONE } // check ALL the required ones are DONE
You could write that check there as a single all condition, but the point is to show you you can be flexible with it, and build up your logic by filtering out the stuff you're not interested in, if you create a useful set of states
If you really do want to (or have to) stick with the current "pairs of variables" setup, you can do something similar:
// wiring them up again, creating a list of Pairs so we can iterate over them easily
val allProcesses = listOf(
::shouldStartProcessA to ::isADone,
::shouldStartProcessB to ::isBDone,
::shouldStartProcessC to ::isCDone
)
// gotta check 'em all - only returns true if that ALL meet the condition
val allComplete = allProcesses.all { (shouldStart, isDone) ->
// the get() syntax is awkward, but basically for everything we're checking
// if it either doesn't need to start, or it does but it's also done
!shouldStart.get() || (shouldStart.get() && isDone.get())
}
so adding new processes is just a case of adding their variables to the list of pairs, and they get included in the checking
You don't need the property reference stuff (::/.get()) if you create the lists right before you check them, but if you want to define them once in advance (and the property values can change after that) then that's how you'd do it. Otherwise you can just do the normal shouldStartProcessA to isADone etc, which is probably fine for most cases - I'm showing the reference stuff as a more general example for handling this kind of thing
I suppose, you should create two lists of Boolean and add variables consequently.
val list1 = listOf(shouldStartProcessA, shouldStartProcessB, shouldStartC)
val list2 = listOf(isADone, isBDone, isCDone)
Then iterate over both lists and check that items in corresponding positions have the same values.
var n = 0
for (i in list1.indices) {
if (list1[i] == list2[i]) {
n++
} else {
n = 0
break
}
}
if (n > 0) {
// Every process completed
}

When performing a collections operation, is it possible to modify the underlying collection?

For example, I have the following code to recursively copy a directory's contents.
private fun copyContentDirectory(directory : File): List<File> {
val files = directory.listFiles().toList()
val filesToTransform = mutableListOf<File>()
// Add each file + directory. Then, recursively add the files in each directory.
files
.onEach { filesToTransform += it }
.filter { it.isDirectory }
.forEach { filesToTransform += copyContentDirectory(it) }
return filesToTransform
}
Is it possible to have something like the following? If not, why not?
private fun copyContentDirectory(directory : File): List<File> {
return directory.listFiles().toList()
.filter { it.isDirectory }
.onEach { <thisList> += copyContentDirectory(it) }
}
Where thisList is some symbol that allows me to reference the underlying list. Does such a thing exist?
As per comments, your intentions aren't very clear.
Looking at the second example, the obvious answer would seem to be to replace this line:
.onEach { <thisList> += copyContentDirectory(it) }
with one using flatMap(), e.g.:
.flatMap{ copyContentDirectory(it) }
That collects together the results from all the recursive calls, and returns them as a single list — which I think is what you want.
However, that just reveals deeper problems:
Despite the name, the method isn't actually copying anything, just collecting together a list.
The list will always be empty — it recurses over directories, but never returns any files, so will only every be combining empty lists.
Here's a version which addresses the second problem. I've also renamed it, recast it as an extension function, and used partition() to avoid filtering twice.  (The first result is those files matching the predicate, i.e. directories, over which it recurses; the second is files not matching, i.e. non-directories, which it includes directly.)  And because listFiles() can return null in some circumstances, it has to handle that too.
private fun File.listContents(): List<File>
= listFiles()
?.partition{ it.isDirectory }
?.let{ it.first.flatMap{ it.listContents() } + it.second }
?: listOf()
(That doesn't address the copying, but the question doesn't indicate how you plan to approach that.)

How I can delete duplicates in a Object list by date in Kotlin with collection operators?

I have a object list with the same id, then, i want to keep the one with the most recent date, and the delete the other with the kotlin collection operators. For Example I have :
{"id":111,
"date":"02/12/2017"
}
and the other
{"id":111,
"date":"02/8/2018"}
In this case, i would like to delete the first object.
You can achieve it like this
list.groupBy { it.id }.entries.map { it.value.maxBy { it.date } }
it will create a map of id, List<object> while keeping original order and then choose newest object from the list.
Here I am assuming date is long value timestamp
If you really must remove the entries from the current collection the following may help you (I assume your objects (Obj) are contained in a list called list):
list.removeAll { anObj -> list.any { anObj.id == it.id && it.date > anObj.date } }
// or same with removeIf
It's probably easier just collecting what you are actually interested in and then have an immutable list in the first place.
Collecting the elements you are interested in could be done as follows (there are of course lots of other ways to do that... just one of many):
val result = list.groupBy { it.id }.values.mapNotNull { it.maxBy { it.date } } // mapNotNull is only used due to maxBy returning a nullable type... it isn't really needed... or well... depends on what your date type is ;-)
result will then be a List<Obj>. Instead of mapNotNull you could also use it.maxBy { it.date }!! if you know there is at least 1 element.
If you then still need to remove the elements from the list, you could do the following:
list.removeIf { it !in result }
// or
list.removeAll { it !in result }
However I can't really recommend that you mutate your current list just for that... The result in the above example already contains all the elements in the form you want (i.e. List<Obj>). Instead rather use the benefit of having an immutable list :-)

Optimizing a method with boolean flag

I have a method whose purpose is to retrieve collection items.
A collection can contain a mix of items, let's say: pens, pencils, and papers.
The 1st parameter allows me to tell the method to retrieve only the itemTypes I pass (e.g, just pens and pencils).
The 2nd parameter flags the function to use the collection's default item types, instead.
getCollectionItems($itemTypes,$useCollectionDefaultItemTypes) {
foreach() {
foreach() {
foreach() {
// lots of code...
if($useCollectionDefaultItemTypes) {
// get collection's items using collection->itemTypes
}
else {
// get collection's items using $itemTypes
}
// lots of code...
}
}
}
}
What feels odd is that if I set the $useCollectionDefaultItemTypes to true, there is no need for the function to use the first parameter. I was considering refactoring this method into two such as:
getCollectionItems($itemTypes); // get the items using $itemTypes
getCollectionItems(); // get the items using default settings
The problem is that the methods will have lots of duplicate code except for the if-statement area.
Is there a better way to optimize this?
Pass in $itemTypes as null when you're not using it. Have your if statement check if $itemTypes === null; if it is, use default settings.
If this is php, which I assume it is, you can make your method signature function getCollectionItems($itemTypes = null) and then you can call getCollectionItems() and it will call it as if you had typed getCollectionItems(null).
It's generally a bad idea to write methods that use flags like that. I've seen that written in several places (here at #16, Uncle Bob here and elsewhere). It makes the method hard to understand, read, and refactor.
An alternative design would be to use closures. Your code could look something like this:
$specificWayOfProcessing = function($a) {
//do something with each $a
};
getCollectionItems($processer) {
foreach() {
foreach() {
foreach() {
// lots of code...
$processor(...)
// lots of code...
}
}
}
}
getCollectionItems($specificWayOfProcessing);
This design is better because
It's more flexible. What happens when you need to decide between three different things?
You can now test the code inside the loop much easier
It is now easier to read, because the last line tells you that you are "getting collection items using a specific way of processing" - it reads like an English sentence.
Yes, there is a better way of doing this -- though this question is not an optimization question, but a style question. (Duplicated code has little effect on performance!)
The simplest way to implement this along the lines of your original idea is to make the no-argument form of getCollectionItems() define the default arguments, and then call the version of it that requires an argument:
getCollectionItems($itemTypes) {
foreach() {
foreach() {
foreach() {
// lots of code...
// get collection's items using $itemTypes
}
// lots of code...
}
}
}
getCollectionItems() {
getCollectionItems(collection->itemTypes)
}
Depending on what language you are using, you may even be able to collapse these into a single function definition with a default argument:
getCollectionItems($itemTypes = collection->itemTypes) {
foreach() {
foreach() {
foreach() {
// lots of code...
// get collection's items using $itemTypes
}
// lots of code...
}
}
}
That has the advantage of clearly expressing your original idea, which is that you use $itemTypes if provided, and collection->itemTypes if not.
(This does, of course, assume that you're talking about a single "collection", rather than having one of those foreach iterations be iterating over collections. If you are, the idea to use a null value is a good one.)