2016-11-05 3 views
1

У меня есть Scala массив 2-кортежей, как это:Scala HashMap из массива

(("A", "2015-11-01"), ("B", "2016-11-11"), ("A", "2017-11-01"), ("B", "2013-11-11")) 

Я хочу, чтобы создать карту, где ключевые карты до последней даты. Так, в приведенном выше примере, результат должен быть:

Map ("A" -> "2017-11-01", "B" -> "2016-11-11") 

Я знаю, как сделать это итеративно - но что бы Scala-полосным (функционально-путь), чтобы сделать это?

+0

Вы уже что-то пробовали? С какими проблемами вы столкнулись? – maasg

ответ

3

Первый ключ группы, а затем выберите последнюю дату.

arr 
    .groupBy(_._1) 
    .map { case (k, v) => k -> v.maxBy(_._2)._2 } 

использование mapValues, чтобы сделать его короче

arr.groupBy(_._1).mapValues(_.maxBy(_._2)._2) 

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

Scala РЕПЛ

scala> val arr = Array(("A", "2015-11-01"), ("B", "2016-11-11"), ("A", "2017-11-01"), ("B", "2013-11-11")) 
arr: Array[(String, String)] = Array((A,2015-11-01), (B,2016-11-11), (A,2017-11-01), (B,2013-11-11)) 

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

arr 
    .groupBy(_._1) 
    .map { case (k, v) => k -> v.maxBy(_._2)._2 } 


// Exiting paste mode, now interpreting. 

res0: scala.collection.immutable.Map[String,String] = Map(A -> 2017-11-01, B -> 2016-11-11) 

дата преобразования не требуется, но если вы хотите, чтобы преобразовать его затем идти вперед.

преобразования Дата:

//ensure correct date format is given to this method if not it will throw match error at runtime. 
def convertStringDateToMillis(str: String): Long = { 
val regex = "(\\d{4})-(\\d{2})-(\\d{2})".r.unanchored 
val regex(year, month, day) = str 
val calendar = Calendar.getInstance() 
calendar.clear() 
calendar.set(Calendar.MONTH, month.toInt) 
calendar.set(Calendar.YEAR, year.toInt) 
calendar.set(Calendar.DAY_OF_MONTH, month.toInt) 
calendar.getTimeInMillis(); 
} 

Решение:

val arr = Array(("A", "2015-11-01"), ("B", "2016-11-11"), ("A", "2017-11-01"), ("B", "2013-11-11")) 

arr.groupBy(_._1).map { case (k, v) => k -> v.maxBy(convertStringDateToMillis(_._2))._2 } 

Scala РЕПЛ

scala> def convertStringDateToMillis(str: String): Long = { 
    | val regex = "(\\d{4})-(\\d{2})-(\\d{2})".r.unanchored 
    | val regex(year, month, day) = str 
    | val calendar = Calendar.getInstance() 
    | calendar.clear() 
    | calendar.set(Calendar.MONTH, month.toInt) 
    | calendar.set(Calendar.YEAR, year.toInt) 
    | calendar.set(Calendar.DAY_OF_MONTH, month.toInt) 
    | calendar.getTimeInMillis(); 
    | } 
convertStringDateToMillis: (str: String)Long 

scala> val arr = Array(("A", "2015-11-01"), ("B", "2016-11-11"), ("A", "2017-11-01"), ("B", "2013-11-11")) 
arr: Array[(String, String)] = Array((A,2015-11-01), (B,2016-11-11), (A,2017-11-01), (B,2013-11-11)) 


scala> arr.groupBy(_._1).map { case (k, v) => k -> v.maxBy(x => convertStringDateToMillis(x._2))._2 } 
res3: scala.collection.immutable.Map[String,String] = Map(A -> 2017-11-01, B -> 2016-11-11) 
+0

, когда я делаю «arr.groupBy (_._ 1)», он жалуется на часть «_1» и говорит: «Значение _1 не входит в Продукт с Serializable». «Arr» имеет тип ArrayBuffer .. так что я делаю «arr.toArray», прежде чем я вызову функцию groupBy, но все же вижу эту ошибку. Благодарю. –

+1

@ Darth.Vader .. ваш массив должен быть таким: val arr = Array ((«A», «2015-11-01»), («B», «2016-11-11»), («A», , «2017-11-01»), («B», «2013-11-11»)) ' – pamu

+0

Моя переменная arr выглядит так: Array ((A, 2015-11-01), (B, 2016- 11-11), (A, 2017-11-01), (B, 2013-11-11)) –

0

Что-то, как это должно работать:

array 
    .groupBy(_._1) 
    .mapValues(_.map(_._2).max) 
Смежные вопросы