Home > Blockchain >  How can I find an element of a particular type in a list, and also smart cast the result?
How can I find an element of a particular type in a list, and also smart cast the result?

Time:01-29

Suppose I have a List<Animal>, and I want to find the first Dog in it. I then want to access some Dog-specific properties of the found Dog.

find doesn't really work:

val dog = animals.find { it is Dog }
// dog is of type "Animal?", but I want "Dog?"

I could use filterIsInstance:

val dog = animals.filterIsInstance<Dog>().firstOrNull()

But that goes through the whole animal list. I want it to stop when it finds the first dog. What is a built in method that does this?

CodePudding user response:

You can use sequences for lazy evaluations

Compare following code samples:

Eager

val firstString = listOf(1, "2", 3, "4", 5, "6")
        // following operations are applied to List
        .filterIsInstance<String>()
        .onEach { println(it) }
        .firstOrNull()

println("Result: $firstString")

Output:

2
4
6
Result: 2

Lazy

val firstString = listOf(1, "2", 3, "4", 5, "6")
        .asSequence()
        // following operations are applied to Sequence
        .filterIsInstance<String>()
        .onEach { println(it) }
        .firstOrNull()

println("Result: $firstString")

Output:

2
Result: 2

In both cases result is the same, but for lazy case no further steps are made after first match is found.

CodePudding user response:

You can use firstNotNullOfOrNull (which is a mouthful to say :D), with as? instead of is.

val dog = animals.firstNotNullOfOrNull { it as? Dog }

It applies the transformation to each element, and returns the first not-null transformation result, or null if there is no such result.

There is also the counterpart firstNotNullOf that throws an exception when there are no not-null results.

  •  Tags:  
  • Related