Eu tenho um iterador de strings, onde cada string pode ser "H"
(cabeçalho) ou "D"
(detalhe). Quero dividir esse iterador em blocos, onde cada bloco começa com um cabeçalho e pode ter de 0 a muitos detalhes.
Eu sei como resolver esse problema carregando tudo na memória. Por exemplo, o código abaixo:
Seq("H","D","D","D","H","D","H","H","D","D","H","D").toIterator
.foldLeft(List[List[String]]())((acc, x) => x match {
case "H" => List(x) :: acc
case "D" => (x :: acc.head) :: acc.tail })
.map(_.reverse)
.reverse
retorna 5 blocos - List(List(H, D, D, D), List(H, D), List(H), List(H, D, D), List(H, D))
- é o que eu quero.
No entanto, em vez de List[List[String]]
no resultado, quero uma Iterator[List[String]]
ou outra estrutura que permita avaliar o resultado preguiçosamente e não carregar toda a entrada na memória se o iterador inteiro for consumido , quero carregar na memória apenas o bloco que está sendo consumido de cada vez (por exemplo: quando ligo iterator.next
).
Como posso modificar o código acima para alcançar o resultado desejado?
Edição: Eu preciso disso no Scala 2.11 especificamente, como o ambiente que eu uso gruda nele. Fico feliz em também aceitar respostas para outras versões.
Respostas:
Aqui está a implementação mais simples que pude encontrar (é genérica e preguiçosa):
use-o assim:
aqui está specyfication:
scalafiddle com testes e comentários adicionais: https://scalafiddle.io/sf/q8xbQ9N/11
(se a resposta for útil, faça um voto positivo. Passei um pouco de tempo com isso :))
SEGUNDA IMPLEMENTAÇÃO:
Você propôs uma versão que não usa
sliding
. Aqui está, mas ele tem seus próprios problemas listados abaixo.Traços:
T>:Null
tipos. Nós só precisamos adicionar um elemento que feche a última coleção no final (nulo é perfeito, mas limita nosso tipo).Aqui está o scalafiddle: https://scalafiddle.io/sf/q8xbQ9N/11
fonte
scanLeft
e ligar para o startGroup apenas uma vez, sem verificar o tamanho. É impressionante como eu não conseguia resolvê-lo antes e, graças à sua resposta, agora posso ver possíveis otimizações. Obrigado!Se você estiver usando o Scala 2.13.x, poderá criar um novo
Iterator
desdobrando-se sobre o originalIterator
.teste:
fonte
Acho que a
scanLeft
operação pode ajudar nesse caso, se você quiser usar a versão Scala 2.11.Gostaria de chegar à próxima solução, mas receio que pareça mais complicado que o original:
Tipos adicionados, por exemplo, legibilidade. Espero que esta ajuda!
fonte