дополнительные параметры desc для кода Ege Özcan
function dynamicSort(property, desc) {
if (desc) {
return function (a, b) {
return (a[property] > b[property]) ? -1 : (a[property] < b[property]) ? 1 : 0;
}
}
return function (a, b) {
return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
}
}
Используя стандартную библиотеку lib, вы можете сделать это следующим образом:
// convert maps to seq, to keep duplicate keys and concat
val merged = Map(1 -> 2).toSeq ++ Map(1 -> 4).toSeq
// merged: Seq[(Int, Int)] = ArrayBuffer((1,2), (1,4))
// group by key
val grouped = merged.groupBy(_._1)
// grouped: scala.collection.immutable.Map[Int,Seq[(Int, Int)]] = Map(1 -> ArrayBuffer((1,2), (1,4)))
// remove key from value set and convert to list
val cleaned = grouped.mapValues(_.map(_._2).toList)
// cleaned: scala.collection.immutable.Map[Int,List[Int]] = Map(1 -> List(2, 4))
Вы можете использовать scalaz :
import scalaz._, Scalaz._
val m1 = Map('a -> 1, 'b -> 2)
val m2 = Map('b -> 3, 'c -> 4)
m1.mapValues{List(_)} |+| m2.mapValues{List(_)}
// Map('b -> List(2, 3), 'c -> List(4), 'a -> List(1))
Вы можете использовать Set(_)
вместо List(_)
, чтобы получить Set
s в качестве значений в Map
.
См. Полугруппу в шпаргалке скалаза (или в изучении скаляза ) для подробностей об операторе |+|
.
Для Int
|+|
работает как +
, для List
- как ++
, для Map
он применяет |+|
к значениям тех же ключей.
Это простейшая реализация, которую я мог придумать,
val m1 = Map(1 -> "1", 2 -> "2")
val m2 = Map(2 -> "21", 3 -> "3")
def merge[K, V](m1:Map[K, V], m2:Map[K, V]):Map[K, List[V]] =
(m1.keySet ++ m2.keySet) map { i => i -> (m1.get(i).toList ::: m2.get(i).toList) } toMap
merge(m1, m2) // Map(1 -> List(1), 2 -> List(2, 21), 3 -> List(3))
Один простой способ сделать это с кошками :
import cats.implicits._
Map(1 -> "Hello").combine(Map(2 -> "Goodbye"))
//Map(2 -> Goodbye, 1 -> Hello)
Важно отметить, что обе карты должны быть одного типа (в данном случае, Map[Int, String]
).
Длинное объяснение:
combine
на самом деле не член Map. Импортируя cats.implicits, вы вводите в область действия встроенные моноидные экземпляры Map котов, а также некоторые неявные классы, которые включают краткий синтаксис.
Вышеуказанное эквивалентно следующему:
Monoid[Map[Int, String]].combine(Map(1 -> "Hello"), Map(2 -> "Goodbye"))
Где мы используем функцию Monoid "summoner" , чтобы получить экземпляр Monoid [Map [Int, String]] в объем и используя его функцию объединения.
Я написал сообщение в блоге об этом, посмотрите его:
http://www.nimrodstech.com/scala-map-merge/
в основном используя полугруппу скалазов, вы можете достичь этого довольно легко
будет выглядеть примерно так:
import scalaz.Scalaz._
Map1 |+| Map2
Вы можете использовать foldLeft для объединения двух карт одного типа
def merge[A, B](a: Map[A, B], b: Map[A, B])(mergef: (B, Option[B]) => B): Map[A, B] = {
val (big, small) = if (a.size > b.size) (a, b) else (b, a)
small.foldLeft(big) { case (z, (k, v)) => z + (k -> mergef(v, z.get(k))) }
}
def mergeIntSum[A](a: Map[A, Int], b: Map[A, Int]): Map[A, Int] =
merge(a, b)((v1, v2) => v2.map(_ + v1).getOrElse(v1))
Пример:
val a = Map("a" -> 1, "b" -> 5, "c" -> 6)
val b = Map("a" -> 4, "z" -> 8)
mergeIntSum(a, b)
res0: Map[String,Int] = Map(a -> 5, b -> 5, c -> 6, z -> 8)
Если вы не хотите возиться с оригинальными картами, вы можете сделать что-то вроде следующего
val target = map1.clone()
val source = map2.clone()
source.foreach(e => target += e._1 -> e._2)
left.keys map { k => k -> List(left(k),right(k)) } toMap
Это сжато и будет работать, предполагая, что ваши две карты left
и right
. Не уверен насчет эффективности.
class1
, class2
), Для первого случая рассмотрим следующий пример:
val left = Map("foo" ->1, "bar" ->2)
val right = Map("bar" -> 'a', "foo" -> 'b')
Что приводит к
res0: Map[String,List[Int]] = Map(foo -> List(1, 98), bar -> List(2, 97))
Обратите внимание, как Char
были преобразованы в Int
с из-за иерархии типов scala. В более общем случае, если в вашем примере class1
и class2
не связаны, вы получите обратно List[Any]
; это, вероятно, не то, что вы хотели.
Вы можете обойти это, исключив конструктор List
из моего ответа; это вернет Tuple
с сохранением типа:
res0: Map[String,(Int, Char)] = Map(foo -> (1,b), bar -> (2,a))
Вторая проблема - это то, что происходит, когда у вас есть карты, которые не имеют одинаковых ключей. Это приведет к исключению key not found
. Другими словами, вы делаете левое, правое или внутреннее соединение двух карт? Вы можете устранить неоднозначность типа объединения, переключившись на right.keys
или right.keySet ++ left.keySet
для правого / внутреннего соединения соответственно. В последнем случае обойдется проблема с отсутствующим ключом, но, возможно, это не то, что вам нужно, т. Е. Может быть, вы хотите использовать левое или правое соединение вместо этого. В этом случае вы можете рассмотреть возможность использования метода withDefault
из Map
, чтобы каждый ключ возвращал значение, например, None
, но это требует немного больше работы.
m2.foldLeft(m1.mapValues{List[CommonType](_)}) { case (acc, (k, v)) =>
acc.updated(k, acc.getOrElse(k, List.empty) :+ v)
}
Как отметил jwvh, тип списка должен быть указан явно, если Class1 не является верхней границей типа для Class2. CommonType - это тип, который является верхней границей как для Class1, так и для Class2.
Начиная с Scala 2.13
, другое решение, основанное только на стандартной библиотеке, состоит в использовании groupMap
, который (как следует из его названия) является эквивалентом groupBy
, за которым следует mapValues
:
// val m1 = Map(1 -> "a", 2 -> "b")
// val m2 = Map(2 -> "c", 3 -> "d")
(m1.toSeq ++ m2).groupMap(_._1)(_._2)
// Map[Int,Seq[String]] = Map(2 -> List("b", "c"), 1 -> List("a"), 3 -> List("d"))
Это:
Объединяет две карты в виде последовательности кортежей (List((1,"a"), (2,"b"), (2,"c"), (3,"d"))
). Для краткости m2
неявно преобразуется в Seq
для адаптации к типу m1.toSeq
- но вы можете сделать это явно, используя m2.toSeq
.
group
элементов на основе их первой части кортежа (_._1
) (групповая часть group Map)
map
s группирует значения для их второй части кортежа (_._2
) (часть карты группы Map )