Scala: итерация индексов массива для простоты понимания, но убедитесь, что тип результата совпадает с типом массива - PullRequest
0 голосов
/ 29 июня 2018

Я знаю, что тип последовательности первой последовательности, найденной в для понимания, определяет выходной тип понимания. Но мне нужно обойти это, не жертвуя использованием синтаксиса понимания.

Предположим, у меня есть некоторые Array[Double], называемые v, и некоторая сложная функция предиката, называемая condition, которая основана на индексах из v, и если condition(i) оценивается как true, то Я хочу сохранить элемент v. Это похоже на использование filter, за исключением того, что фильтрация происходит по индексам, а не по значениям v.

Я хочу выразить это эффективно для понимания по индексам, но я хочу, чтобы тип результата был Array[Double], а не тип Array.indices.

Вот минимальный пример, где condition - просто игрушечный пример вычисления четности индекса. Реальные варианты использования включают проверку индексов в двумерном массиве, где выполняются определенные условия градиента изображения, но идея такая же, как в этом простом примере.

scala> val v = Array[Double](8.0, 9.0, 10.0, 11.0, 12.0)
v: Array[Double] = Array(8.0, 9.0, 10.0, 11.0, 12.0)

scala> def condition(x: Int): Boolean = {x % 2 == 0} // but could be complex
condition: (x: Int)Boolean

scala> for (i <- v.indices if condition(i)) yield v(i)
res136: scala.collection.immutable.IndexedSeq[Double] = Vector(8.0, 10.0, 12.0)

Вывод для for-compition - типа scala.collection.immutable.IndexedSeq[Double], но я ищу, как убедиться, что он будет Array[Double], без необходимости явного приведения типа.

По сути, если я итерирую с foo.indices, а полученные элементы получены с foo(i), я ищу способ автоматически использовать тип foo для результата, чтобы тип контейнера соответствовал индексам любого типа. были повторены.

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

1 Ответ

0 голосов
/ 29 июня 2018
  1. Используйте zipWithIndex. В случае Array он выдаст Array[(Double, Int)], а не странное IndexedSeq:

    for ((a, i) <- v.zipWithIndex if condition(i)) yield a
    
  2. Использование breakOut

    import collection.breakOut
    val res: Array[Double] = (
      for (i <- v.indices if condition(i)) yield v(i)
    )(breakOut)
    
  3. Просто конвертируйте результат в конце с toArray, оптимизируйте его позже, когда это окажется действительно необходимым.

  4. Также обратите внимание, что zipWithIndex можно определить в целом для всех коллекций, которые имеют класс типов Traverse . Это общий метод преобразования F[A] в F[(A, Int)] при условии, что доступно Traverse[F].

...