Scala 如何使元素包含'$';字符作为键,在键后面';什么数字作为列表?

Scala 如何使元素包含'$';字符作为键,在键后面';什么数字作为列表?,scala,Scala,有一个数组,如何使元素包含“$”字符作为键,并在键后面的数字作为列表 val a = Array("$A", 1234, "$B", 123, 4, 5) 预期: Map("$A"->List(1234),"$B"->List(123,4,5))) thx为所有回答者,以下是我的最终代码: a.toList.tails.collect { case (key: String) :: rest if key.contains('$') => (key, rest.take

有一个数组,如何使元素包含“$”字符作为键,并在键后面的数字作为列表

val a = Array("$A", 1234, "$B", 123, 4, 5)
预期:

Map("$A"->List(1234),"$B"->List(123,4,5)))
thx为所有回答者,以下是我的最终代码:

a.toList.tails.collect {
  case (key: String) :: rest if key.contains('$') => (key, rest.takeWhile(!_.toString.contains('$')))
}.toMap

您可以使用
foldLeft
(假设
Array[Any]
作为输入):

需要使用
反转
,因为
(将元素添加到列表的开头)比将元素添加到末尾要快,但是
列表[Int]
会以这种方式反转

另一个选项是对的尾部递归调用

注意,
Map
不能保证插入顺序(即使对于键,不管它是迭代器),因此不能将其用于累加器(不能从中获取
键。最后一个
元素):

但是,您可以使用
ListMap
,但是
键。last
list.head
(恒定时间)慢(线性时间)


p.S.2请记住,您的
a.toList.tails.collect…
版本会重新访问某些元素2-3次:1次是collect跳过整数,1次是takeWhile检测序列结束,因此可能会影响性能。

这可以通过简单的折叠实现:

val a = Array("$A", 1234, "$B", 123, 4, 5)

a.foldLeft((Map.empty[String, List[Int]], Option.empty[String])) {
  case ((map, _), ele: String) if ele.startsWith("$") => 
    (map + (ele -> List[Int]()), Some(ele))
  case ((map, Some(lastKey)), ele: Int) =>
    (map + (lastKey -> (map(lastKey) :+ ele)), Some(lastKey))
} _1
结果是一个
Map($a->List(1234),$B->List(123,4,5))

折叠阵列中的元素。如果元素包含“$”,则创建新列表并保存密钥以供以后使用。在
Int
的情况下,将元素添加到
lastKey
的列表中。获取结果元组的第一个元素,以除去
lastKey

  • 首先找到
    $
    的索引。示例
    列表((“$A”,0),(“$B”,2))
  • 并找到每个
    $
    的范围<代码>(“$A”,0,2),(“$B”,2,6))
  • 然后用上面的
    $
    范围对数组进行切片
  • 举个例子

    val input = Array("$A", 1234, "$B", 123, 4, 5)
    
    val index$Elems = input.zipWithIndex.map {case (elem, index) =>
      if (elem.toString.startsWith("$")) elem.toString -> index
    } filter(!_.isInstanceOf[BoxedUnit])
    
    val groupElems = index$Elems.zipWithIndex.map {
      case (kv: (String, Int), index: Int) if index != index$Elems.length - 1 =>
        Tuple3(kv._1, kv._2, index$Elems(index + 1).asInstanceOf[(String, Int)]._2)
    
      case (keyvalue: (String, Int), index) if index == index$Elems.length - 1 =>
        Tuple3(keyvalue._1, keyvalue._2, input.length)
    
    } map { elems: (String, Int, Int) =>
      Map(elems._1 -> input.slice(elems._2 + 1, elems._3).toList)
    }
    
    测验


    您尝试了什么?只是为了澄清一下,为什么最初不使用映射(参见我的答案)?@thwiegan
    Map
    不保留插入顺序(除了像3个元素这样的小集合),即
    keys
    迭代器实际上是
    集合
    。这就是为什么我总是喜欢
    List
    。有一个解决方法(ListMap),但是它比常规的
    Map
    @thwiegan有开销,所以你不能使用
    键。last
    在裸
    Map
    上(
    HashMap
    )@thwiegan也有
    键。last
    ListMap
    中花费线性时间,谢谢你提供的信息:)相应地更新了我的答案。
    val a = Array("$A", 1234, "$B", 123, 4, 5)
    
    a.foldLeft((Map.empty[String, List[Int]], Option.empty[String])) {
      case ((map, _), ele: String) if ele.startsWith("$") => 
        (map + (ele -> List[Int]()), Some(ele))
      case ((map, Some(lastKey)), ele: Int) =>
        (map + (lastKey -> (map(lastKey) :+ ele)), Some(lastKey))
    } _1
    
    val input = Array("$A", 1234, "$B", 123, 4, 5)
    
    val index$Elems = input.zipWithIndex.map {case (elem, index) =>
      if (elem.toString.startsWith("$")) elem.toString -> index
    } filter(!_.isInstanceOf[BoxedUnit])
    
    val groupElems = index$Elems.zipWithIndex.map {
      case (kv: (String, Int), index: Int) if index != index$Elems.length - 1 =>
        Tuple3(kv._1, kv._2, index$Elems(index + 1).asInstanceOf[(String, Int)]._2)
    
      case (keyvalue: (String, Int), index) if index == index$Elems.length - 1 =>
        Tuple3(keyvalue._1, keyvalue._2, input.length)
    
    } map { elems: (String, Int, Int) =>
      Map(elems._1 -> input.slice(elems._2 + 1, elems._3).toList)
    }
    
    groupElems.head("$A") shouldBe List(1234)
    groupElems.last("$B") shouldBe List(123, 4, 5)