Haskell'的Scala实现;s群比

Haskell'的Scala实现;s群比,scala,haskell,Scala,Haskell,我正在寻找Haskell的groupBy的Scala实现 行为应该是这样的: isD :: Char -> Bool isD c = elem c "123456789-_ " groupBy (\a b -> isD a == isD b) "this is a line with 0123344334343434343434-343 3345" ["this"," ","is"," ","a"," ","line"," ","with"," 012334433434343434

我正在寻找Haskell的groupBy的Scala实现

行为应该是这样的:

isD :: Char -> Bool
isD c = elem c "123456789-_ "

groupBy (\a b -> isD a == isD b) "this is a line with 0123344334343434343434-343 3345"
["this"," ","is"," ","a"," ","line"," ","with"," 0123344334343434343434-343 3345"]
我尝试了Scala groupBy函数,但是它只接受一个参数的函数,而不是Haskell的2。我还研究了分区,但是它只返回一个元组


我正在寻找的函数应该将匹配谓词的每个连续元素分组。

将Haskell版本转换为Scala肯定不会太难。这是我的建议。它使用
span
;我不知道Scala中是否有与
span
相当的版本,也不知道您是否需要翻译该版本。

我的版本,只是在胡闹而已--不太确定。我比Scala更了解Haskell,但尝试学习Scala:

object GroupByTest extends App {    
  val ds = Set('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_', ' ')

  def isD(d: Char) = ds contains d

  def hgroupBy[A](op: A => (A => Boolean), a: List[A]): List[List[A]] = 
    a match {
      case Nil => List.empty
      case x :: xs =>
        val t = xs span op(x)         
        (x :: t._1) :: hgroupBy(op, t._2)        
    }

  val lambda: Char => Char => Boolean = x => y => isD(x) == isD(y)

  println(hgroupBy(lambda, "this is a line with 0123344334343434343434-343 3345".toList))
}

这样的问题似乎经常出现,这很好地表明Rex Kerr的
groupedWhile
方法应该包含在标准集合库中。但是,如果您不想将其复制/粘贴到您的项目中

我喜欢您的递归解决方案,但它实际上并没有输出正确的内容(即字符串),因此我将如何更改它:

def groupBy(s: String)(f: (Char, Char) => Boolean): List[String] = s match {
  case "" => Nil
  case x => 
    val (same, rest) = x span (i => f(x.head, i))
    same :: groupBy(rest)(f)
}
然后,使用您的函数并在REPL中进行尝试:

val isD = (x: Char) => "123456789-_ " contains x
groupBy("this is a line with 0123344334343434343434-343 3345")(isD(_) == isD(_))

结果是一个
列表[String]
,这大概是您真正想要的。

现在使用它,感谢您的回答:

def groupByS(eq: (Char,Char) => Boolean, list: List[Char]): List[List[Char]] = {
    list match {
    case head :: tail => {
      val newHead = head :: tail.takeWhile(eq(head,_))
      newHead :: groupByS(eq, tail.dropWhile(eq(head,_)))
    }
    case nil => List.empty
  }
}

这可能可以改进;)

这是不寻常的,但答案已经存在(对于任意类型,包括字符串),作为回答另一个问题的示例:(注意,该方法名为
groupedWhile
)感谢您指出这一点,显然不是我搜索的术语;)@哈马尔:谢谢你的指点。删除了答案并将其移到下面单独的一个。这里还有几个实现:有一个Scala版本的
span
,但由于Haskell和Scala类型系统之间的差异,在一般情况下很难保持所有类型的正确性。感谢您的回答。我已经搞定了一些正在为这个特定案件工作的东西。
def partitionBy[T, U](list: List[T])(f: T => U ): List[List[T]] = {

  def partitionList(acc: List[List[T]], list: List[T]): List[List[T]] = {
    list match {
      case Nil => acc
      case head :: tail if f(acc.last.head) == f(head) => partitionList(acc.updated(acc.length - 1, head :: acc.last), tail)
      case head :: tail => partitionList(acc ::: List(head) :: Nil, tail)
    }
  }

  if (list.isEmpty) List.empty
  else partitionList(List(List(list.head)), list.tail)
}

partitionBy("112211".toList)(identity)
//res: List[List[Char]] = List(List(1, 1), List(2, 2), List(1, 1))


val l = List("mario", "adam", "greg", "ala", "ola")

partitionBy(l)(_.length)
//res: List[List[String]] = List(List(mario), List(greg, adam), List(ola, ala))