isD a == isD b) "this is a line with 0123344334343434343434-343 3345" ["this"," ","is"," ","a"," ","line",""> isD a == isD b) "this is a line with 0123344334343434343434-343 3345" ["this"," ","is"," ","a"," ","line",""> isD a == isD b) "this is a line with 0123344334343434343434-343 3345" ["this"," ","is"," ","a"," ","line","" />

HaskellのgroupByのScala実装

私は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ではなく、1つの引数の関数しか使用しませんでした。私もパーティションを見ていましたが、タプルを返します。

私が探している関数は、述語に一致する各連続要素をグループ化する必要があります。

6
追加された 著者 Todd Owen,
これは重要なことではありませんが、別の質問に答えるための例として、(文字列を含む任意の型の)回答が既に存在しています: stackoverflow.com/questions/ 5410846 (このメソッドの名前は groupedWhile です)。
追加された 著者 Rex Kerr,
これを指摘してくれてありがとう、明らかに私が検索した用語ではない;)
追加された 著者 Sander,
ポインタのための@ハマールありがとう。答えを削除し、下の別の場所に移動しました。
追加された 著者 Sander,

5 答え

このような質問はかなり頻繁に出てくるようですが、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(_))

結果は List [String] です。おそらくあなたが望んでいたものです。

2
追加された
スパンの素敵な使い方!私はそれが好きです!
追加された 著者 Sander,

これは答えのおかげで今のところこれを使いました:

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
  }
}

これはおそらく改善することができます;)

2
追加された

HaskellのバージョンをScalaに翻訳するのは難しくありません。 ハスケルの定義> groupBy をクリックします。 span を使用します。 Scalaに span と同等のものがあるかどうか、または Haskellの span の定義も同様です。

1
追加された
Scalaバージョンの span がありますが、一般的なケースでは、HaskellとScalaタイプのシステムの違いにより、すべてのタイプをまっすぐに保つのは難しいです。
追加された 著者 Rex Kerr,
答えをありがとう。私は、この特定のケースのために作業する途中の何かをハッキングしました。
追加された 著者 Sander,

私のバージョン、ちょうど回っている - それについてあまり確かではない。私はHaskellをScalaより良く知っていますが、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))
}
0
追加された
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))
0
追加された