2015-08-30 4 views
1

У меня есть функция, которая принимает список списков целых чисел, в частности Seq[Seq[Int]]. Затем я беру эти данные из чтения текстового файла и используя split, и который создает список Array. Это не признано Scala, которое вызывает ошибку совпадения. Но либо IndexedSeq, либо Array остались в порядке с функцией Seq[Int], видимо, только вложенная коллекция является проблемой. Как я могу конвертировать неявно IndexedSeq[Array[Int]] в Seq[Seq[Int]], или как еще я могу это сделать, кроме как использовать toList, как показано ниже? Например, Iterable[Iterable[Int]] кажется прекрасным, но я не могу это использовать.Как легко преобразовать IndexedSeq [Array [Int]] в Seq [Seq [Int]] в Scala?

scala> def g(x:Seq[Int]) = x.sum 
g: (x: Seq[Int])Int 

scala> g("1 2 3".split(" ").map(_.toInt)) 
res6: Int = 6 

scala> def f(x:Seq[Seq[Int]]) = x.map(_.sum).sum 
f: (x: Seq[Seq[Int]])Int 

scala> f(List("1 2 3", "3 4 5").map(_.split(" ").map(_.toInt))) 
<console>:9: error: type mismatch; 
found : List[Array[Int]] 
required: Seq[Seq[Int]] 
       f(List("1 2 3", "3 4 5").map(_.split(" ").map(_.toInt))) 
             ^

scala> f(List("1 2 3", "3 4 5").map(_.split(" ").map(_.toInt).toList)) 
res8: Int = 18 
+0

Интересная проблема. Я думаю, что это больше связано с неизменяемыми коллекциями vs mutable, чем с чем-либо еще. – marios

+0

Обратите внимание, как 'f (List (" 1,2,3 ".split (", "). Map (_. ToInt)," 1,2,3 ".split (", "). Map (_. ToInt))) 'фактически работает ... – marios

+0

Сумасшедшая вещь, если вы _assign_ это и передаете значение как параметр, это не сработает. Но если вы встраиваете это выражение в вызов функции, это работает !! ?? Я предполагаю, что, разбив первую карту и запустив выражение внутри вызова функции, вывод типа и неявные преобразования по умолчанию могут работать с их магией, но не иначе ... Я не думаю, что когда-либо видел пример чего-то подобного раньше ! – dividebyzero

ответ

2

Проблема заключается в том, что Array не реализует SeqLike. Обычно неявные преобразования в ArrayOps или WrappedArray, определенные в scala.predef, позволяют использовать массив точно так же, как Seq. Однако в вашем случае массив «скрыт» от неявных преобразований как общий аргумент. Одним из решений было бы намекнуть компилятор, который вы можете применить неявное преобразование в общий аргумент, как это:

def f[C <% Seq[Int]](x:Seq[C]) = x.map(_.sum).sum 

Это похоже на ответ Павла выше. Проблема заключается в том, что ограничения зрения устарели в Scala 2.11, и использование устаревших языковых функций не является хорошей идеей.К счастью, вид оценки можно переписать в виде контекстных границ следующим образом:

def f[C](x:Seq[C])(implicit conv: C => Seq[Int]) = x.map(_.sum).sum 

Теперь, это предполагает, что существует неявное преобразование из C в Seq[Int], который действительно присутствует в predef.

+0

Теперь это то, что я искал. Поэтому, если я правильно понимаю, обычно 'Array' может быть передан' Seq', и мы даже не заботимся о неявном преобразовании (это _really_ implicit). Но когда он попадает внутрь контейнера, компилятор не знает, что делать, и нам нужно дать руку, чтобы он мог применить обычное преобразование, и мы получаем WrappedArray. Благодаря! – dividebyzero

1

Как об этом:

implicit def _convert(b:List[Array[Int]]):Seq[Seq[Int]]=b.map(_.toList) 
+0

Ну, что ж, для написания нами неявного кода преобразования, так как это должно быть полезно. Я фактически закончил использование 'def fun [T] (xx: Traversable [Seq [T]]) = xx map (_.reverse)' и 'implicit def _convert [T] (b: Traversable [Array [T]]) : Traversable [Seq [T]] = b.map (_. ToVector) '. Но в моем вопросе надеялись полностью избежать «toList», даже неявно ... – dividebyzero

+0

Если вы просто замените '_.toList' на создание' WrappedArray' из входного массива 'Array', то это будет идеально. – dividebyzero

1

Redefine е, чтобы быть немного более гибким.

С Traversable является родительским элементом List, Seq, Array и т. Д., F будет совместим с этими контейнерами, если он основан на Traversable. Traversable имеет сумму, сглаживание и карту, и это все, что нужно.

Что сложно об этом заключается в том, что

def f(y:Traversable[Traversable[Int]]):Int = y.flatten.sum 

является привередлив и не работает на ау типе List[Array[Int]] хотя он будет работать на Array[List[Int]]

Чтобы сделать его менее привередлив, некоторый тип вида оценки будет работать.

Первоначально я заменил вашу сумму сумм на операцию сплющивания/суммы.

def f[Y<%Traversable[K],K<%Traversable[Int]](y:Y):Int=y.flatten.sum 

Я нашел это также, кажется, работает, но я не проверял, как много:

def f[Y <% Traversable[K], K <% Traversable[Int]](y:Y):Int=y.map(_.sum).sum 

Этого <% синтаксис говорит Y является viewable, как проходимый [K] для некоторого типа K, который можно просмотреть в виде Пересечение Int.

Определите несколько различных контейнеров, в том числе и вам нужно:

scala> val myListOfArray = List(Array(1,2,3),Array(3,4,5)) 
val myListOfArray = List(Array(1,2,3),Array(3,4,5)) 
myListOfArray: List[Array[Int]] = List(Array(1, 2, 3), Array(3, 4, 5)) 

scala> val myArrayOfList = Array(List(1,2,3),List(3,4,5)) 
val myArrayOfList = Array(List(1,2,3),List(3,4,5)) 
myArrayOfList: Array[List[Int]] = Array(List(1, 2, 3), List(3, 4, 5)) 

scala> val myListOfList = List(List(1,2,3),List(3,4,5)) 
val myListOfList = List(List(1,2,3),List(3,4,5)) 
myListOfList: List[List[Int]] = List(List(1, 2, 3), List(3, 4, 5)) 

scala> val myListOfRange = List(1 to 3, 3 to 5) 
val myListOfRange = List(1 to 3, 3 to 5) 
myListOfRange: List[scala.collection.immutable.Range.Inclusive] = List(Range(1, 2, 3), Range(3, 4, 5)) 

Тест:

scala> f(myListOfArray) 
f(myListOfArray) 
res24: Int = 18 

scala> f(myArrayOfList) 
f(myArrayOfList) 
res25: Int = 18 

scala> f(myListOfList) 
f(myListOfList) 
res26: Int = 18 

scala> f(myListOfRange) 
f(myListOfRange) 
res28: Int = 18 
+0

FYI, ограничения просмотра устарели: https://issues.scala-lang.org/browse/SI-7629. Вместо этого вы должны использовать неявные параметры, в соответствии с этим протектором: https://groups.google.com/forum/#!topic/scala-internals/hNow9MvAi6Q/discussion – Tim

+0

@Tim Интересное чтение, большинство для устаревания и несколько отставших, которые говорят, что рамки обзора будут улучшаться и сохраняться среди других драгоценных камней. Я только начинаю изучать несколько более сложных частей scala, а неурегулированные части и синтаксические изменения не совсем соблазнительны. С удовольствием играю с ним как своего рода головоломку, но интерес может закончиться там ... – Paul

+0

Из этой дискуссии я почувствовал, что решение осудить рамки обзора недвусмысленно, хотя это не произойдет до 2.14 или около того. Выше я дал еще один ответ, который делает «unsugaring» символа%, если вам интересно. – Tim

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