2013-05-26 2 views
3

С первого раза я прочитал, что:Scala для постижений и flatMap/карта промежуточные результаты

for { 
    harpo<-list1 if harpo.length>0 
    groucho<-list2 
    chico<-list3 
} yield (harpo, groucho, chico) 

переводит:

list1.filter(_.length>0).flatMap(harpo =>  
     list2.flatMap(groucho=>list3.map((harpo,groucho,_))) 
) 

Я беспокоился о ненужных промежуточных коллекций, возвращенных filter, flatMap & map. Первый был зафиксирован в Scala 2.8 (?), Добавив метод withFilter, и я подозреваю, что происходит некоторая магия, которая меняет тип возвращаемого значения этих методов в зависимости от использования, поэтому при использовании в качестве параметра flatMap они возвращают не- строгая коллекция, но я не могу найти никаких доказательств. Являются ли мои подозрения правильными, и это не так неэффективно, как кажется на первый взгляд?

ответ

4

Это относится к this question. В частности, the answer по @IODEV показывает вам, как посмотреть на Обессахаренной форме:

$ scala -Xprint:typer -e 
'val list1 = List("foo", "bar"); val list2 = list1; val list3 = list1; 
for (harpo<-list1 if harpo.length>0; groucho <- list2; chico <- list3) 
yield (harpo, groucho, chico)' 

(без перерывов) линий

list1.withFilter(_.length() > 0) 
    .flatMap(harpo => 
    list2.flatMap(groucho => 
     list3.map(chico => (harpo, groucho, chico)) 
    ) 
) 

Я не вижу никаких растрат промежуточных коллекций, которые вы могли бы сохранить, если вы не хотите использовать изменчивый строитель и while или foreach звонки для заполнения этого строителя:

val b = List.newBuilder[(String, String, String)] 
for(harpo <- list1 if harpo.length() > 0; groucho <- list2; chico <- list3) { 
    b += ((harpo, groucho, chico)) 
} 
b.result() 

Вопрос в том, имеет ли ваш конкретный код существенную проблему с производительностью. Например. ваши коллекции огромны. Если нет, перейдите с более идиоматической формой (for ... yield). Оптимизируйте только разработчику с for ... {}, когда вы действительно получите что-то от него.

+0

Возможно, я должен был быть более ясным. Мой вопрос: коллекции, возвращенные list3.map и list2.flatMap в этом случае строгие или нет? Если они строги, они многократно создаются, чтобы их отбросить после помещения их элементов в родительскую коллекцию. Если я просто делаю 'val l = list3.map (« brother »+ _)' Я получаю строгую коллекцию. Типичным примером C++ в таких случаях является использование ленивого промежуточного типа, который неявно трансформируется в строгий тип при назначении переменной ожидаемого типа возврата. Я не знаю, возможно ли это в scala, но для его вывода типа все еще есть секреты для меня. – Turin

+0

'list2' и' list3', вероятно, строгие (вы не указываете их типы, но при условии, что они имеют тип 'List'), поэтому внутренние петли создают строгие промежуточные результаты. Я не знаю коллекций C++, но сомневаюсь, что вы можете разложить «flatMaps» ленивым способом, который устраняет любые промежуточные коллекции - __'map'__ и __'filter'__ yes, но не __'flatMap'__. Если вы этого хотите, используйте итерационный подход с построителем и 'foreach'. Как я уже сказал, не увлекайтесь преждевременными оптимизациями. –

Смежные вопросы