是否有针对Guava MultiSet和Table概念的scala替代品?

时间:2014-01-14 11:19:48

标签: scala guava scala-collections

在scala中使用guava TableMultiset? scala中是否已有不同的概念,而不是为此用法导入java库?

2 个答案:

答案 0 :(得分:5)

您可以使用Map[(R, C), V]代替Table<R, C, V>Map[T, Int]代替Multiset<T>。您还可以像Map[T, Int]一样向implicit class Multiset[T](val m: Map[T, Int]) extends AnyVal { def setAdd(e: T, i: Int = 1) = { val cnt = m.getOrElse(e, 0) + i if (cnt <= 0) m - e else m.updated(e, cnt) } def setRemove(e: T, i: Int = 1) = setAdd(e, -i) def count(e: T) = m.getOrElse(e, 0) } val m = Map('a -> 5) m setAdd 'a // Map('a -> 6) m setAdd 'b // Map('a -> 5, 'b -> 1) m setAdd ('b, 10) // Map('a -> 5, 'b -> 10) m setRemove 'a // Map('a -> 4) m setRemove ('a, 6) // Map() m count 'b // 0 (m setAdd 'a) count 'a // 6 添加辅助方法:

{{1}}

答案 1 :(得分:1)

这是第一个使用Map[(R, C), V]作为委托集合的简单实现。 rowscolumns用作m: Map的索引。

package utils.collections

import utils.collections.Table.Cell

class Table[R, C, V](val m: Map[(R, C), V], val rows: Map[R, List[(R, C)]], val columns: Map[C, List[(R, C)]]) {

  def containsValue(value: V): Boolean = m.values.exists(_.equals(value))

  def values(): List[V] = m.values.toList

  def get(rowKey: R, columnKey: C): Option[V] = m.get(rowKey, columnKey)

  def apply(rowKey: R, columnKey: C): V = m.apply((rowKey, columnKey))

  def cellSet(): Set[Cell[R, C, V]] = m.map { case ((r, c), v) => Cell(r, c, v) }.toSet

  def contains(rowKey: R, columnKey: C): Boolean = m.contains((rowKey, columnKey))

  def put(rowKey: R, columnKey: C, value: V): Table[R, C, V] = {
    val keys: (R, C) = (rowKey, columnKey)
    new Table(
      m = m + ((keys, value)),
      rows = rows + ((rowKey, keys::rows.getOrElse(rowKey, List.empty))),
      columns = columns + ((columnKey, keys::columns.getOrElse(columnKey, List.empty)))
    )
  }

  def putAll(table: Table[_ <: R, _ <: C, _ <: V]): Table[R, C, V] = Table(m.++(xs = table.m))

  def remove(rowKey: R, columnKey: C): Table[R, C, V] = {
    val keys: (R, C) = (rowKey, columnKey)
    val updatedRows: Map[R, List[(R, C)]] = rows.get(rowKey) match {
      case Some(keysWithRow) if keysWithRow.diff(List(keys)).nonEmpty => rows + ((rowKey, keysWithRow.diff(List(keys))))
      case _ => rows - rowKey
    }
    val updatedColumns: Map[C, List[(R, C)]] = columns.get(columnKey) match {
      case Some(keysWithColumn) if keysWithColumn.diff(List(keys)).nonEmpty => columns + ((columnKey, keysWithColumn.diff(List(keys))))
      case _ => columns - columnKey
    }
    new Table(
      m = m - keys,
      rows = updatedRows,
      columns = updatedColumns
    )
  }

  def row(rowKey: R): Map[C, V] = m.filterKeys(k => rows.get(rowKey).exists(_.equals(k))).map { case ((_, c), v) => (c, v) }

  def containsRow(rowKey: R): Boolean = rows.exists(_.equals(rowKey))

  def rowMap(): Map[R, Map[C, V]] = m.groupBy { case ((r, _), _) => r }.map { case (r, subMap) => (r, subMap.map { case ((_, c), v) => (c, v) }) }

  def rowKeySet(): Set[R] = rows.keySet

  def column(columnKey: C): Map[R, V] = m.filterKeys(k => columns.get(columnKey).exists(_.equals(k))).map { case ((r, _), v) => (r, v) }

  def containsColumn(columnKey: C): Boolean = columns.exists(_.equals(columnKey))

  def columnMap(): Map[C, Map[R, V]] = m.groupBy { case ((_, c), _) => c }.map { case (c, subMap) => (c, subMap.map { case ((r, _), v) => (r, v) }) }

  def columnKeySet(): Set[C] = columns.keySet

  def size(): Int = m.size

  def isEmpty: Boolean = m.isEmpty

}

object Table {

  case class Cell[R, C, V](rowKey: R, columnKey: C, value: V)

  def empty[R, C, V] = new Table[R, C, V](Map.empty, Map.empty, Map.empty)

  def apply[R, C, V](m: Map[(R, C), V]): Table[R, C, V] = {
    val rows: Map[R, List[(R, C)]] = m.keys.groupBy { case (r, c) => r }.map { case (r, keys) => r -> keys.toList }
    val columns: Map[C, List[(R, C)]] = m.keys.groupBy { case (r, c) => c }.map { case (c, keys) => c -> keys.toList }
    new Table[R, C, V](m, rows, columns)
  }

}