2012-10-22 52 views
2

我看到Scala的標準庫偏出獲得集合中的對象的範圍的方法,滿足謂詞:這個操作的好名字是什麼?

def <???>(p: A => Boolean): List[List[A]] = { 
    val buf = collection.mutable.ListBuffer[List[A]]() 
    var elems = this.dropWhile(e => !p(e)) 
    while (elems.nonEmpty) { 
    buf += elems.takeWhile(p) 
    elems = elems.dropWhile(e => !p(e)) 
    } 
    buf.toList 
} 

什麼是這種方法的好名字?我的執行足夠好嗎?

回答

7

我會去chunkWithchunkBy

至於你實現,我覺得這迫切要求遞歸!看看你能不能填寫此

@tailrec def chunkBy[A](l: List[A], acc: List[List[A]] = Nil)(p: A => Boolean): List[List[A]] = l match { 
    case Nil => acc 
    case l => 
    val next = l dropWhile !p 
    val (chunk, rest) = next span p 
    chunkBy(rest, chunk :: acc)(p) 
} 

爲什麼遞歸?理解算法要容易得多,而且更容易無錯(因爲沒有變量)。

的語法!P在謂語的否定通過隱式轉換實現

implicit def PredicateW[A](p: A => Boolean) = new { 
    def unary_! : A => Boolean = a => !p(a) 
} 

我一般保持這個局面,因爲它是令人歎爲觀止的有用

+1

優秀的實施!一個註釋 - 我相信你忘記在無情況下添加「反向」。 – Rogach

2

如何:

def chunkBy[K](f: A => K): Map[K, List[List[A]]] = ... 

groupBy類似,但保持連續塊爲塊。 使用這個,你可以做xs.chunkBy(p)(true)得到你想要的。

+0

我喜歡這一個了,我會跟旁邊添加它'chunkWith'(chunkWith在功能上dropWhile/takeWhile相似,所以它應該聽起來像他們一樣,'chunkBy'是m礦石類似於'groupBy')。但我認爲,在我的具體情況下避免地圖會更好一點的表現。 – Rogach

2

你可能想叫它splitWith因爲split是字符串操作或多或少地做到了這一點,它與splitAt類似。

順便說一句,這裏是一個非常緊湊的實現(雖然它做了很多不必要的工作,所以它不是一個速度的良好執行;你是罰款爲):

def splitWith[A](xs: List[A])(p: A => Boolean) = { 
    (xs zip xs.scanLeft(1){ (i,x) => if (p(x) == ((i&1)==1)) i+1 else i }.tail). 
    filter(_._2 % 2 == 0).groupBy(_._2).toList.sortBy(_._1).map(_._2.map(_._1)) 
} 
+0

我傾向於聲明函數fst和snd,例如「def fst [A,B](ab:(A,B))= ab._1」。這樣,像「x groupBy(_._ 1)」這樣的代碼變成「x groupBy fst」。提高代碼的可讀性;我討厭_1和_2! –

1

只是有點細化故道的代碼,這樣的簽名較輕

def chunkBy[A](xs: List[A])(p: A => Boolean): List[List[A]] = { 
    @tailrec 
    def recurse(todo: List[A], acc: List[List[A]]): List[List[A]] = todo match { 
    case Nil => acc 
    case _ => 
     val next = todo dropWhile (!p(_)) 
     val (chunk, rest) = next span p 
     recurse(rest, acc ::: List(chunk)) 
    } 
    recurse(xs, Nil) 
} 
+0

是的,顯然我會把我的大塊當作內在的def –