Как заполнить ListBuffer [List [Any]] (Scala)? - PullRequest
1 голос
/ 20 октября 2019

У меня ListBuffer объявлен так:

var distances_buffer: ListBuffer[List[Any]] = ListBuffer.empty[List[Any]]

, и я пытаюсь заполнить его такими данными:

for(current <- 0 to training_list_length - 1){
   //A and B are examples
   distances_buffer(current) ++= List[Any](A,B)
}

Однако я получаю следующую ошибку:

java.lang.IndexOutOfBoundsException: 0

Чего мне не хватает?

РЕДАКТИРОВАТЬ! Дополнительная информация:

У меня есть список (названный: training_list) точек и их класса. (x, y, класс):

training_list : List[((Double, Double, String))]

У меня также есть дополнительная точка с заданным значением ax и yy.

Моя цель - рассчитать евклидово расстояние дополнительной точки от каждой точки в списке тренировок и создать результат, который выглядит следующим образом:

//example
List((x: Double, y: Double, class: String), distance: String)

List((4.3,3.0,Iris-setosa), 1.2529964086141665), (4.4,3.0,Iris-setosa), 1.341640786499874)...

Как вы можете видеть, вв список я хочу включить координаты точки (из training_list), класс точки, а также расстояние.

for(current <- 0 to training_list_length - 1){
    val dist = eDistance(test_x, test_y, training_x(current), training_y(current))
    distances_buffer += ListBuffer[Any](training_result(current),dist)
  }

После создания этого списка я хочу отсортировать его по расстоянию. Также застрял здесь!

Ответы [ 2 ]

3 голосов
/ 20 октября 2019

Кажется, для того, как вы называете вещи, вы пришли из Python фона.

Я бы посоветовал вам немного изучить Scala во-первых, так как мы очень разные.
Не только по стилю (например, верблюжий случай или тире) , но и по более фундаментальным вещам, таким как:

  • Сильный исистема статического типа. Таким образом, такие вещи, как Any, обычно являются запахом кода, а в 99,99% случаев совершенно не нужны.
  • Смесь OOP и FP. Таким образом, вам не обязательно становиться экспертом по FP, но есть некоторые вещи, которые являются идиоматическими даже на стороне ООП Scala , например неизменяемость и обычные операции (вышефункции заказа) как map, flatMap, filter & reduce.
  • Наш Список очень отличается от Python oneдоступ к элементу по индексу равен O(n) Python это будет O(1)) . Список Python больше похож на Array , размер которого можно изменить.
  • Кроме того, у нас на самом деле нет цикла for. У нас есть что-то под названием для понимания , которое является не более чем синтаксическим сахаром для вызовов map, flatMap, filter & inнекоторые случаи foreach.

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


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

// First lets create some custom types / classes to represent your data.
final case class Point(x: Double, y: Double)
final case class ClassifiedPoint(point: Point, clazz: String)

// Lets define the Euclidean distance function.
def euclideanDistance(p1: Point, p2: Point): Double =
  math.sqrt(
    math.pow((p1.x - p2.x), 2) +
    math.pow((p1.y - p2.y), 2)
  )
}

// This is what you need.
// Note that I made it somewhat more generic that is has to be.
// For example, instead of using the euclidean distance function directly on the body,
// we receive the distance function to use.
// Also, I use a technique called currying to split the arguments in different lists,
// This allows the caller to partially apply them.
def computeDistance(distanceFun: (Point, Point) => Double)
                   (trainingList: List[ClassifiedPoint])
                   (referencePoint: Point): List[(ClassifiedPoint, Double)] =
  trainingList.map { classifiedPoint =>
    val distance = distanceFun(classifiedPoint.point, referencePoint)
    classifiedPoint -> distance
  }

Который вы можете использовать следующим образом.

val trainingList = List(
  ClassifiedPoint(Point(x = 4.3d, y = 3.0d), clazz = "Iris-setosa"),
  ClassifiedPoint(Point(x = 4.4d, y = 3.0d), clazz = "Iris-setosa")
)

// Partial application to create a new function.
val computeEuclideanDistance = computeDistance(euclideanDistance) _

computeEuclideanDistance(trainingList, Point(x = 3.0d, y = 0.0d))
// res: List[(ClassifiedPoint, Double)] =
//   List(
//     (ClassifiedPoint(Point(4.3, 3.0), "Iris-setosa"), 3.269556544854363),
//     (ClassifiedPoint(Point(4.4, 3.0), "Iris-setosa"), 3.3105890714493698)
//   )
2 голосов
/ 20 октября 2019

Как предполагает Луис, по возможности следует избегать Any и var, поэтому здесь приведен пример, который может подтолкнуть вас к рассмотрению другого подхода

case class Point(x: Double, y: Double, `class`: String)

def distance(a: Point, b: Point): Double =
  math.hypot(a.x - b.x, a.y - b.y)

val targetPoint = Point(1,2,"Extra-point")
val training_list : List[((Double, Double, String))] = List((4.3,3.0,"Iris-setosa"), (4.4,3.0,"Iris-setosa"))
val points = training_list.map(Point.tupled)
val unsortedPoints: List[(Point, Double)] = points.map(point => (point, distance(point, targetPoint)))
unsortedPoints.sortBy(_._2)

, который выдает

res0: List[(Point, Double)] = List((Point(4.3,3.0,Iris-setosa),3.4481879299133333), (Point(4.4,3.0,Iris-setosa),3.5440090293338704))

Я скопировал расчет расстояния из Ксавье .

...