I'd like to check a List<Int?> for nulls and if no nulls exist, then allow the List to proceed as a List<Int>, otherwise use an emptyList()
This is what I came up with:
var noNullElements: List<Int> = emptyList()
if (listWithPossibleNullElements.all { it != null }) {
noNullElements = listWithPossibleNullElements as List<Int>
}
//do something with noNullElements list
I'd be shocked if this was the best, most idiomatic way.
Solution
There are many acceptable solutions below, but the one I chose was a combination of the solutions
fun getSafeList(list: List<Int?>): List<Int> =if (null in list) emptyList() else list.requireNoNulls()
Here's a one liner extension function:
inline fun <reified T : Any> Iterable<T?>.filterNoneNull(): Iterable<T>? =
takeIf { null !in it }?.requireNoNulls()
takeIf {} - a scope function that will return null if the lambda evaluates to false
null !in it - use the in operator function to determine if the list contains null
finally, if takeIf {} returns a non-null value, filterNotNull() will convert the element type from the nullable T? to non-null T
Note that it will return null if the provided Iterable<T?> contains null, else List<T>, in case it's important to differentiate between the provided list being empty, or containing null. An alternative can be provided using the elvis operator.
Example usage - run in Kotlin Playground:
fun main() {
val listA: List<Int?> = listOf(1, 2, 3, null)
// since listA contains 'null', the result is 'null'
println(listA.filterNoneNull())
// prints: null
// provide an alternative, using the elvis operator
println(listA.filterNoneNull() ?: emptyList<Int>())
// prints: []
val listB: List<Int> = listOf(1, 2, 3)
// since listB does not contain null, the same list is returned
println(listB.filterNoneNull())
// prints: [1, 2, 3]
}
inline fun <reified T : Any> Iterable<T?>.filterNoneNull(): Iterable<T>? =
takeIf { null !in it }?.requireNoNulls()
Note: I edited the question and replaced filterNotNull() with requireNoNulls(), as the latter will not instantiate a new list
Check with contains for the existence of at least one null value:
val noNullElements = if (list.contains(null)) emptyList() else list.map { it!! }
Edit: Added this extension function:
fun List<Int?>.castToIntOrEmpty() =
if (this.contains(null)) emptyList() else this.map { it as Int }
val noNullElements = list.castToIntOrEmpty()
Example with no null elements:
val list: List<Int?> = List(10) { it }
// list is: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
val noNullElements = if (list.contains(null)) emptyList() else list.map { it!! }
println(noNullElements) // Output: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Example with some (or all) null elements:
val list: List<Int?> = List(10) { if (it % 2 == 0) it else null }
// list is: [0, null, 2, null, 4, null, 6, null, 8, null]
val nullElements = if (list.contains(null)) emptyList() else list.map { it!! }
println(nullElements) // Output: []
I think your problem is you want to take a generic List<Int?> type and treat it as a List<Int>, which means casting it. Because List<Int?> isn't a subtype of List<Int> (although the inverse is true, as Joffrey points out in the comments) you basically have to perform an unchecked cast in this situation:
if (list.contains(null)) emptyList else list as List<Int>
The compiler isn't smart enough to determine that this is a safe cast at runtime (and you have to be able to make that guarantee yourself, e.g. ensuring the list isn't being modified elsewhere to include a null after the check passes) so you'll get an unchecked cast warning. The documentation on generics goes into your options, but if you really want to pass in a List<Int?> and treat it as a List<Int>, you'll have to suppress that warning:
An unchecked cast warning can be suppressed by annotating the statement or the declaration where it occurs with #Suppress("UNCHECKED_CAST")
I'd argue the more idiomatic approach is to just create a new List<Int> instead of trying to cast the original one to a different generic type, or to make the original list provider pass a List<Int>? instead (i.e. null if there were any non-null elements) which is maybe just moving the problem - but it really depends on what you're doing.
You can easily create filtered copies and compare it to the original to decide whether to use it, or write a for loop building a new list that short-circuits if you hit a null, all those kinds of things. If you want to check first and only copy if you need it, lukas.j's answer has more examples (including a couple that throw exceptions, like requireNoNulls()) so you have a lot of options, and there are different tradeoffs - it really depends on what you're doing and where the bottlenecks are (if any). Things can get a bit awkward when you work with generics, so some situations don't end up looking as neat as you'd like!
Try using filterNotNull:
val noNullElements: List<Int> = listWithPossibleNullElements.filterNotNull()
Related
I have two Lists and I want to get the List containing only the elements in the first list that are not in the second one. The problem is that I need to specify a custom equal when subtracting. Let's suppose I want to use one of the fields in the entries of the lists. Let's say the id.
I implemented it this way:
list1.filter { log -> list2.none { it.id == log.id } }
or
val projection = logEntries.map { it.id }
list1.filter { it.id !in projection }
Is there a better way to do it? Please take into account that I can't set a new equal method for the class.
The way you do it is ok, but when the lists become bigger you might want to do that:
You could make the process more efficient by turning your reference list (list2) to a set first.
val referenceIds = list2.distinctBy { it.id }.toSet()
list1.filterNot { it.id in referenceIds }
Background:
An ArrayList which you are most likely using has a time complexity of O(n) when you check if an element is contained. So, if the list gets bigger, it will take longer.
A HashSet on the other hand has a time complexity of O(1) when checking if an element is contained. So, if list2 becomes bigger it won't get slower.
Another approach?
fun main() {
val list1 = listOf(0, 1, 2, 3, 4, 5)
val list2 = listOf(2,3,4)
println(list1.filterNotIn(list2))
}
fun <T> Collection<T>.filterNotIn(collection: Collection<T>): Collection<T> {
val set = collection.toSet()
return filterNot { set.contains(it) }
}
Output: [0, 1, 5]
As per comments, there's no built-in way to do this. (Probably not for any fundamental reason; just because no-one saw a need.)
However, you can easily add one yourself. For example, here's your first suggestion, converted to extension function:
fun <T, R> Collection<T>.minus(elements: Collection<T>, selector: (T) -> R?)
= filter{ t -> elements.none{ selector(it) == selector(t) } }
You could then call this in the same way that a built-in function would work:
list1.minus(list2){ it.id }
(There are probably more efficient implementations, but this illustrates the idea.)
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/minus.html
fun main() {
val list1 = listOf(0, 1, 2, 3, 4, 5)
val list2 = listOf(2,3,4)
println(list1.minus(list2))
}
I need a little assistance.
I've been working out the functional aspects in Scala. Almost all the work is in lists and for the most part, I can work out the problems, but I hit a small dead-end. I can't keep the original form (structure) of the list in certain problems. In the output all the nested lists get flattened. Concatenate ::: flattens the list(that is an element of the original list) and append :: gives me a compilation error, as it requires a generic T type (not a list).
A very simple example, in which I want to remove the first element of a list that matches the input:
def removeFirst[T](obj: T, list: List[T]): List[T] = {
if (list isEmpty) Nil
else{
val fin: List[T] = list.head match {
case headAsList: List[T] => if (containsWithNestedLists(obj, headAsList))
removeFirst(obj, headAsList) ::: list.tail
else headAsList ::: removeFirst(obj, list.tail)
case _ => if (list.head == obj) list.tail
else if (list.tail == List()) List(list.head)
else list.head :: removeFirst(obj, list.tail)
}
fin
}
}
For one level deep lists, it works fine, but
the output that comes out for
removeFirst(1,List(List(1,2,3),1,2,3,4,5,6)) is List(2, 3, 1, 2, 3, 4, 5, 6), where as ideally I would want List(List(2,3),1,2,3,4,5,6)).
Or the more specific input removeFirst(1,List(List(2,3,List()),List(1,2,3),1,2,3,4,5,6,List(2,3,List())))
should have output = List(List(2,3,List()),List(2,3),1,2,3,4,5,6,List(1,2,3,List()))
Also I have found that removing the generic T and using Any in its place does the trick, but I also know that Any is a big no-no and a temporary solution for a permanent problem, as in other functions it hasn't helped.
As far as I know, I haven't seen a helpful solution on the internet, so I have to ask. Am I missing something, need to debug or is there another function that could help me? The closest I've come to my answer is using append :: in some manner, but I may be wrong.
You examples just look as if you want to remove a certain element from the list if it is present.
For flat lists you can do this much simpler:
def removeFirst[T](obj: T, list: List[T]) = list match {
case `obj` :: rest => rest
case _ => list
}
This will do the following:
> removeFirst(1, List(1, List(1,2,3)))
res57: List[Any] = List(List(1, 2, 3))
> removeFirst(1, List(2, List(1,2,3)))
res58: List[Any] = List(2, List(1, 2, 3))
> removeFirst(List(2,3), List(List(2,3), List(1,2,3)))
res59: List[List[Int]] = List(List(1, 2, 3))
However, it seems you want to do this for arbitrarily nested Lists. This is not directly possible, as Scala cannot express the exact type of that. The type you'd need would be something like
type NestedList[T] = List[T union NestedList[T]]
Scala does not have union types and you cannot do recursive definitions in this way, so you can not just do this either:
type NestedList[T] = List[Either[T, NestedList[T]]]
You can however do it, if you use a class instead of a type:
case class NestedList[T](value: List[Either[T, NestedList[T]]])
Now you can write your algorithm like this:
def removeFirst[T](obj: T, list: NestedList[T]): NestedList[T] = {
val rest = list.value match {
case Left(`obj`) :: tail => tail
case __ => list.value
}
NestedList(rest.map {
case Right(r) => Right(removeFirst(obj, r))
case Left(r) => Left(r)
})
}
And you can do this:
> removeFirst(1, NestedList(List(Left(1), Left(2), Right(NestedList(List(Left(1),Left(3)))))))
res71: NestedList[Int] = NestedList(List(Left(2), Right(NestedList(List(Left(3))))))
It is of course a bit cumbersome to build and decompose these structures. So maybe it would be better to build a proper tree class using a sealed abstract class and two case classes instead of using the Either.
I'm trying to get this class to run but I keep running into issues. I'm new to Java and not sure if I am doing this correctly. If someone could just help me out with the addition of elements to a list I can figure out the rest!
class ListPractice implements Testable {
def mylist = [4,5,6]
/**
* Adds a set of elements to the mylist variable
*
* #param elts The elements to be added
*/
def addToList(List elts) {
def newlist = getMylist()+List
return newlist
}
#Override
void testMe() {
addToList([7,8,9])
assert getMylist() == [4,5,6,7,8,9]
assert getMylist() == [7,8,9]
}
}
You are adding List instead of elts. The method you are looking for is addAll:
groovy:000> l = [1,2,3]
===> [1, 2, 3]
groovy:000> l.addAll([4,5,6])
===> true
groovy:000> l
===> [1, 2, 3, 4, 5, 6]
Since addtoList sounds already as if you plan to mutate this, why create a
new one, return it, and later never use it? So: mylist.addAll(elts) should
be enough.
related:
just write mylist instead of getMylist() - it's groovy
your comment on addToList says set but accepys a list. Sets have
different characteristics than lists, so it's confusing. If you rename it
to addToMylist you might not even need a comment at all.
Let the code speak first
def bars = foo.listBars()
def firstBar = bars ? bars.first() : null
def firstBarBetter = foo.listBars()?.getAt(0)
Is there a more elegant or idiomatic way to get the first element of a list, or null if it's not possible? (I wouldn't consider a try-catch block elegant here.)
Not sure using find is most elegant or idiomatic, but it is concise and wont throw an IndexOutOfBoundsException.
def foo
foo = ['bar', 'baz']
assert "bar" == foo?.find { true }
foo = []
assert null == foo?.find { true }
foo = null
assert null == foo?.find { true }
--Update Groovy 1.8.1
you can simply use foo?.find() without the closure. It will return the first Groovy Truth element in the list or null if foo is null or the list is empty.
You could also do
foo[0]
This will throw a NullPointerException when foo is null, but it will return a null value on an empty list, unlike foo.first() which will throw an exception on empty.
Since Groovy 1.8.1 we can use the methods take() and drop(). With the take() method we get items from the beginning of the List. We pass the number of items we want as an argument to the method.
To remove items from the beginning of the List we can use the drop() method. Pass the number of items to drop as an argument to the method.
Note that the original list is not changed, the result of take()/drop() method is a new list.
def a = [1,2,3,4]
println(a.drop(2))
println(a.take(2))
println(a.take(0))
println(a)
*******************
Output:
[3, 4]
[1, 2]
[]
[1, 2, 3, 4]
I have a list l:List[T1] and currently im doing the following:
myfun : T1 -> Option[T2]
val x: Option[T2] = l.map{ myfun(l) }.flatten.find(_=>true)
The myfun function returns None or Some, flatten throws away all the None's and find returns the first element of the list if any.
This seems a bit hacky to me. Im thinking that there might exist some for-comprehension or similar that will do this a bit less wasteful or more clever.
For example: I dont need any subsequent answers if myfun returns any Some during the map of the list l.
How about:
l.toStream flatMap (myfun andThen (_.toList)) headOption
Stream is lazy, so it won't map everything in advance, but it won't remap things either. Instead of flattening things, convert Option to List so that flatMap can be used.
In addition to using toStream to make the search lazy, we can use Stream::collectFirst:
List(1, 2, 3, 4, 5, 6, 7, 8).toStream.map(myfun).collectFirst { case Some(d) => d }
// Option[String] = Some(hello)
// given def function(i: Int): Option[String] = if (i == 5) Some("hello") else None
This:
Transforms the List into a Stream in order to stop the search early.
Transforms elements using myFun as Option[T]s.
Collects the first mapped element which is not None and extract it.
Starting Scala 2.13, with the deprecation of Streams in favor of LazyLists, this would become:
List(1, 2, 3, 4, 5, 6, 7, 8).to(LazyList).map(function).collectFirst { case Some(d) => d }
Well, this is almost, but not quite
val x = (l flatMap myfun).headOption
But you are returning a Option rather than a List from myfun, so this may not work. If so (I've no REPL to hand) then try instead:
val x = (l flatMap(myfun(_).toList)).headOption
Well, the for-comprehension equivalent is pretty easy
(for(x<-l, y<-myfun(x)) yield y).headOption
which, if you actually do the the translation works out the same as what oxbow_lakes gave. Assuming reasonable laziness of List.flatmap, this is both a clean and efficient solution.
As of 2017, the previous answers seem to be outdated. I ran some benchmarks (list of 10 million Ints, first match roughly in the middle, Scala 2.12.3, Java 1.8.0, 1.8 GHz Intel Core i5). Unless otherwise noted, list and map have the following types:
list: scala.collection.immutable.List
map: A => Option[B]
Simply call map on the list: ~1000 ms
list.map(map).find(_.isDefined).flatten
First call toStream on the list: ~1200 ms
list.toStream.map(map).find(_.isDefined).flatten
Call toStream.flatMap on the list: ~450 ms
list.toStream.flatMap(map(_).toList).headOption
Call flatMap on the list: ~100 ms
list.flatMap(map(_).toList).headOption
First call iterator on the list: ~35 ms
list.iterator.map(map).find(_.isDefined).flatten
Recursive function find(): ~25 ms
def find[A,B](list: scala.collection.immutable.List[A], map: A => Option[B]) : Option[B] = {
list match {
case Nil => None
case head::tail => map(head) match {
case None => find(tail, map)
case result # Some(_) => result
}
}
}
Iterative function find(): ~25 ms
def find[A,B](list: scala.collection.immutable.List[A], map: A => Option[B]) : Option[B] = {
for (elem <- list) {
val result = map(elem)
if (result.isDefined) return result
}
return None
}
You can further speed up things by using Java instead of Scala collections and a less functional style.
Loop over indices in java.util.ArrayList: ~15 ms
def find[A,B](list: java.util.ArrayList[A], map: A => Option[B]) : Option[B] = {
var i = 0
while (i < list.size()) {
val result = map(list.get(i))
if (result.isDefined) return result
i += 1
}
return None
}
Loop over indices in java.util.ArrayList with function returning null instead of None: ~10 ms
def find[A,B](list: java.util.ArrayList[A], map: A => B) : Option[B] = {
var i = 0
while (i < list.size()) {
val result = map(list.get(i))
if (result != null) return Some(result)
i += 1
}
return None
}
(Of course, one would usually declare the parameter type as java.util.List, not java.util.ArrayList. I chose the latter here because it's the class I used for the benchmarks. Other implementations of java.util.List will show different performance - most will be worse.)