Digamos que eu tenha uma Sequence<Int>
origem desconhecida (não necessariamente de uma coleção) e de tamanho desconhecido, mas finito:
val seq = sequenceOf(1, 2, -3, 4, 5, /* ... */)
Suponha que a sequência seja grande o suficiente para tornar indesejável transformar toda a sequência em um arquivo List
.
Quero obter o último elemento da sequência:
val last = seq.last()
Mas também quero capturar qualquer elemento "inválido" que possa aparecer (digamos que números negativos sejam inválidos) e retornar o primeiro elemento:
val invalid = seq.first { it < 0 }
Mas como posso fazer as duas coisas ao mesmo tempo?
val lastUnlessInvalidElementPresent = seq.firstOrNull { it < 0 } ?: seq.last()
O problema é que ?: seq.last()
não funciona porque quando o tempo firstOrNull
retorna nulo, toda a sequência já foi consumida.
Posso fazer isso iterativamente, mas preferiria uma solução funcional.
Não acho que isso possa ser feito facilmente com as funções integradas porque last é um predicado especial.
Adaptar o existente
lastOrNull
para testar a primeira ocorrência de um predicado (it < 0
) ficaria assim:Agora você pode usar
seq.firstOrLastOrNull { it < 0 }
para conseguir o que deseja. Isso não deve ser diferente, em termos de desempenho, das funções integradas.Você pode considerar usar um nome mais descritivo para essa função.
Você pode usar
fold()
uma classe de dados simples que contém seu valor mais um sinalizador indicando se você ainda está no modo "obter o último" ou já no modo "encontrei um valor inválido, vamos mantê-lo":Essa abordagem tem duas desvantagens:
fold()
a sequência completa mesmo depois de encontrar um elemento inválidoParque infantil
No final, encontrei minha própria solução sucinta:
É quase funcional, mas não é puramente funcional porque usa uma variável mutável.