Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

140
Visualizações
¿Cómo limitar una secuencia de Kotlin con un predicado que se preocupa por el siguiente elemento?

Necesito abordar una API que devuelve datos fragmentados.

 val response = server.getChunk(request, chunkNumber) data class PageInfo( val pageNumber: Int, val maxPages: Int ) data class Response( val elements: List<Payload>, val pageInfo: PageInfo )

Supongo que esta API es idempotente.

Puedo hacer algo así ( toma 1 ):

 var i = 0 var maxPages: Int val payloadTotal = mutableListOf<Payload>() do { val response = server.getChunk(request, i++) maxPages = response.pageInfo.maxPages payloadTotal.addAll(response.payload) } while (i < maxPages)

Funciona, pero es feo.

tomar 2 :

 val partners = IntStream .iterate(0) { it + 1 } .asSequence() .map { server.getChunk(request, it) } .takeWhile { it.pageInfo.pageNumber < it.pageInfo.maxPages } .map { it.payload } .flatten() .toList()

Se ve mucho mejor, pero no funciona del todo como se esperaba: dado que verificamos el predicado takeWhile después de solicitar el servidor, siempre terminaremos haciendo una solicitud adicional. Y dado que no conocemos el valor de maxPages antes de hacer la primera solicitud, no podemos usar algo como take(n: Int) .

Así que terminé yendo con ese código ( toma 3 ):

 var maxPages = Int.MAX_VALUE val partners = IntStream .iterate(0) { it + 1 } .asSequence() .takeWhile { it < maxPages } .map { server.getChunk(request, it) .also { response -> maxPages = response.pageInfo.maxPages } } .map { it.payload } .flatten() .toList()

Funciona. Pero, de nuevo, usamos este estado adicional que no me gusta.

Además, debido a las restricciones "efectivamente definitivas", esto no funcionará en Java en absoluto (y me gustaría que lo hiciera como bonificación).

Entonces, ¿cómo logro el comportamiento requerido con un enfoque funcional? ¿Hay alguna manera de hacerlo sin rastrear ningún estado adicional fuera de la canalización?

*Si tal forma existe, ¿también se traduce a Java?

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Podemos crear nuestro propio operador de secuencia para este propósito. Requiere escribir algo de código, pero luego podemos usarlo muy bien:

 generateSequence(0) { it + 1 } .map { server.getChunk(request, it) } .takeNextWhile { it.pageInfo.pageNumber + 1 < it.pageInfo.maxPages } .flatMap { it.elements } .toList() fun <T> Sequence<T>.takeNextWhile(predicate: (T) -> Boolean): Sequence<T> = Sequence { val iter = iterator() var hasNext = iter.hasNext() object : Iterator<T> { override fun hasNext() = hasNext override fun next() = iter.next().also { hasNext = iter.hasNext() && predicate(it) } } }

Alternativamente, podemos takeWhilePrevious() si eso tiene más sentido para nosotros.

Si no queremos crear nuevos operadores, creo que es mejor no usar transformaciones funcionales, ya que empeoran la legibilidad del código en este caso. Suponiendo que maxPages no cambie, primero podemos obtenerlo y luego realizar un ciclo muy simple:

 val first = server.getChunk(request, 0) val payloads = first.elements.toMutableList() (1 until first.pageInfo.maxPages).forEach { payloads += server.getChunk(request, it).elements }
over 4 years ago · Santiago Trujillo Relatório

0

Pequeña solución para que funcione, puede pasar el objeto de respuesta nula como semilla para generateSequence

 val partners = generateSequence(0 to (null as Response?)) { (page, _) -> page+1 to getChunk(page) }.takeWhile { (page, response) -> response == null || page < response.maxPages }.flatMap { it.second?.payload ?: emptyList() }.toList()

(Sin embargo, el objetivo de legibilidad aún no está resuelto). Se puede introducir cierta claridad usando funciones

 data class PageResponse(val page: Int = 0, val response: Response? = null) { fun isNotLastPage() = response == null || page < response.maxPages fun getPayload() = response?.payload ?: emptyList() } val partners = generateSequence(PageResponse()) { (page, _) -> PageResponse(page + 1, getChunk(page)) } .takeWhile(PageResponse::isNotLastPage) .flatMap(PageResponse::getPayload) .toList()
over 4 years ago · Santiago Trujillo Relatório

0

En este caso, probablemente haría una secuencia a partir de un bucle do-while while. Es bastante legible para aquellos que necesitan leer la implementación y bastante útil para aquellos que solo se preocupan por la secuencia:

 fun Server.requestInPages(request: Request, startPage: Int = 0): Sequence<Response> = sequence { var page = startPage do { val response = getChunk(request, page++) yield(response) } while (response.pageInfo.pageNumber < response.pageInfo.maxPages) }

Y luego utilízalo así:

 val partners = server.requestInPages(request) .flatMap { it.elements } .toList()

Si las respuestas son todas iguales, incluso podría agregar otro asistente que contenga flatMap encima de requestInPages . Si a nadie le importa la estructura de respuesta y PageInfo en absoluto, incluso podría hacer que flatMap parte de requestInPages .

Puntos de bonificación: esto incluso podría convertirse en un flujo si su llamada API se convierte en una función de suspend en algún momento (por ejemplo, si cambia a rutinas).

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda