Причина, по которой эта конкретная программа работает медленно, заключается в том, что она работает с примитивами, но использует общие операции, поэтому примитивы должны быть упакованы. (Это можно было бы улучшить, если бы List
и его предки были специализированными.) Это, вероятно, замедлит работу примерно в 5 раз.
Кроме того, алгоритмически эти операции несколько затратны, потому что вы создаете целый список, а затем создаете совершенно новый список, отбрасывая несколько компонентов промежуточного списка. Если бы вы сделали это одним махом, то вам было бы лучше. Вы можете сделать что-то вроде:
list collect (case e if (e*2>10) => e*2)
а что делать, если расчет e*2
действительно дорог? Тогда вы могли бы
(List[Int]() /: list)((ls,e) => { val x = e*2; if (x>10) x :: ls else ls }
за исключением того, что это будет отображаться задом наперёд. (При необходимости вы можете изменить его, но для этого потребуется создать новый список, что опять-таки не идеально алгоритмически.)
Конечно, у вас есть такие же алгоритмические проблемы в Java, если вы используете односвязный список — ваш новый список окажется в обратном порядке, или вам придется создавать его дважды, сначала в обратном, а затем в прямом направлении, или у вас есть построить его с (не хвостовой) рекурсией (что легко в Scala, но нецелесообразно для такого рода вещей на любом языке, поскольку вы исчерпаете стек), или вам нужно создать изменяемый список, а затем притвориться, что он не изменяемый. (Что, кстати, можно сделать и в Scala — см. mutable.LinkedList
.)
person
Rex Kerr
schedule
04.02.2011