Acabei de ler que o tempo de execução da operação de acréscimo para a List
(: +) cresce linearmente com o tamanho da List
.
Anexar a um List
parece ser uma operação bastante comum. Por que a maneira idiomática de fazer isso é preceder os componentes e depois reverter a lista? Também não pode ser uma falha de design, pois a implementação pode ser alterada a qualquer momento.
Do meu ponto de vista, tanto o anexo quanto o anexo devem ser O (1).
Existe alguma razão legítima para isso?
List[T]
pressupõe que você o esteja usando da maneira que usaria em uma linguagem funcional pura - geralmente trabalhando na cabeça com desconstrução e prepends.Respostas:
Vou expandir um pouco meu comentário. A
List[T]
estrutura de dados, fromscala.collection.immutable
é otimizada para funcionar da mesma maneira que uma lista imutável em uma linguagem de programação mais puramente funcional. Tem tempos de pré-inserção muito rápidos , e supõe-se que você estará trabalhando na cabeça por quase todo o seu acesso.As listas imutáveis passam a ter tempos de pré-inserção muito rápidos, devido ao fato de modelarem suas listas vinculadas como uma série de "células contras". A célula define um valor único e um ponteiro para a próxima célula (estilo clássico de lista vinculada individual):
Quando você anexa uma lista, na verdade você está apenas criando uma única célula nova, com o restante da lista existente sendo apontado:
Como a lista é imutável, você pode fazer isso sem nenhuma cópia real . Não há perigo de a lista antiga mudar e fazer com que todos os valores em sua nova lista se tornem inválidos. No entanto, você perde a capacidade de ter um ponteiro mutável para o final da sua lista como um compromisso.
Isso se presta muito bem ao trabalho recursivo em listas. Digamos que você definiu sua própria versão de
filter
:Essa é uma função recursiva que trabalha exclusivamente a partir da cabeça da lista e aproveita a correspondência de padrões por meio do extrator ::. Isso é algo que você vê muito em idiomas como Haskell.
Se você realmente deseja anexos rápidos, o Scala fornece várias estruturas de dados mutáveis e imutáveis para você escolher. No lado mutável, você pode investigar
ListBuffer
. Como alternativa,Vector
fromscala.collection.immutable
tem um tempo de acréscimo rápido.fonte
else
um loop infinito? Eu acho que deveria ser algo assimx::deleteIf(xs)(f)
.head
etail
acesso a este tipo de lista é muito rápido - mais rápido do que usar qualquer mapa com base em hash ou matriz - é um excelente tipo para funções recursivas. Esta é uma razão pela qual as listas são um tipo de núcleo na maioria das linguagens funcionais (por exemplo, Haskell ou Scheme)List
anexar / anexar).