2015-04-21 6 views
0

Почему следующий код не работает, и как его преодолеть с помощью Iterator?Карта привязывается к кортежам с помощью Iterator

def f(str : String) : (String, String) = { 
    str.splitAt(1) 
} 
var with_id : Iterator[(String, Int)] = List(("test", 1), ("list", 2), ("nothing", 3), ("else", 4)).iterator 

println(with_id.mkString(" ")) 

val result = with_id map { (s : String, i : Int) => (f(s), i) } 

println(result.mkString(" ")) 

Ожидаемый результат:

(("t", "est"), 1) (("l", "ist"), 2) ...

Ошибка:

Error:(28, 54) type mismatch; 
found : (String, Int) => ((String, String), Int) 
required: ((String, Int)) => ? 
val result = with_id map { (s : String, i : Int) => (f(s), i) } 
               ^

ответ

2

Проблема заключается в том, что (s : String, i : Int) => (f(s), i) является Function2 (то есть функция, которая принимает 2 аргумента):

scala> (s : String, i : Int) => (f(s), i) 
res3: (String, Int) => ((String, String), Int) = <function2> 

тогда как .map ожидает Function1 (взяв кортеж в качестве аргумента).

Вы можете определить Function1 с

scala> val g = (t: (String, Int)) => (f(t._1), t._2) 
g: ((String, Int)) => ((String, String), Int) = <function1> 

scala> val result = with_id map g 
result: Iterator[((String, String), Int)] = non-empty iterator 

Но, кажется, гораздо лучше (для меня по крайней мере), чтобы использовать более идиоматический шаблон анонимных функций (обратите внимание на добавленный case):

scala> val result = with_id map { case (s : String, i : Int) => (f(s), i) } 
result: Iterator[((String, String), Int)] = non-empty iterator 
+0

Спасибо! Но есть еще одна проблема с моим примером. Первый 'mkString' исчерпывает итератор, заставляя карту запускаться на пустой итератор. – Dyin

1

with_id.map ожидает ((String, Int) => ?) функция как вход. То есть, функция, которая принимает входной сигнал Tuple, а не два параметра.

Вы можете использовать его как это:

with_id map{ case (s,i) => (f(s), i)} //match the input tuple to s and i