How to implement 'takeUntil' of a list? - list

I want to find all items before and equal the first 7:
val list = List(1,4,5,2,3,5,5,7,8,9,2,7,4)
My solution is:
list.takeWhile(_ != 7) ::: List(7)
The result is:
List(1, 4, 5, 2, 3, 5, 5, 7)
Is there any other solution?

One-liner for impatient:
List(1, 2, 3, 7, 8, 9, 2, 7, 4).span(_ != 7) match {case (h, t) => h ::: t.take(1)}
More generic version:
It takes any predicate as argument. Uses span to do the main job:
implicit class TakeUntilListWrapper[T](list: List[T]) {
def takeUntil(predicate: T => Boolean):List[T] = {
list.span(predicate) match {
case (head, tail) => head ::: tail.take(1)
}
}
}
println(List(1,2,3,4,5,6,7,8,9).takeUntil(_ != 7))
//List(1, 2, 3, 4, 5, 6, 7)
println(List(1,2,3,4,5,6,7,8,7,9).takeUntil(_ != 7))
//List(1, 2, 3, 4, 5, 6, 7)
println(List(1,2,3,4,5,6,7,7,7,8,9).takeUntil(_ != 7))
//List(1, 2, 3, 4, 5, 6, 7)
println(List(1,2,3,4,5,6,8,9).takeUntil(_ != 7))
//List(1, 2, 3, 4, 5, 6, 8, 9)
Tail-recursive version.
Just to illustrate alternative approach, it's not any more efficient than previous solution.
implicit class TakeUntilListWrapper[T](list: List[T]) {
def takeUntil(predicate: T => Boolean): List[T] = {
def rec(tail:List[T], accum:List[T]):List[T] = tail match {
case Nil => accum.reverse
case h :: t => rec(if (predicate(h)) t else Nil, h :: accum)
}
rec(list, Nil)
}
}

Borrowing the takeWhile implementation from scala.collection.List and changing it a bit:
def takeUntil[A](l: List[A], p: A => Boolean): List[A] = {
val b = new scala.collection.mutable.ListBuffer[A]
var these = l
while (!these.isEmpty && p(these.head)) {
b += these.head
these = these.tail
}
if(!these.isEmpty && !p(these.head)) b += these.head
b.toList
}

Here's a way to get there with foldLeft, and a tail recursive version to short circuit long lists.
There's also the tests I used while playing around with this.
import scala.annotation.tailrec
import org.scalatest.WordSpec
import org.scalatest.Matchers
object TakeUntilInclusiveSpec {
implicit class TakeUntilInclusiveFoldLeft[T](val list: List[T]) extends AnyVal {
def takeUntilInclusive(p: T => Boolean): List[T] =
list.foldLeft( (false, List[T]()) )({
case ((false, acc), x) => (p(x), x :: acc)
case (res # (true, acc), _) => res
})._2.reverse
}
implicit class TakeUntilInclusiveTailRec[T](val list: List[T]) extends AnyVal {
def takeUntilInclusive(p: T => Boolean): List[T] = {
#tailrec
def loop(acc: List[T], subList: List[T]): List[T] = subList match {
case Nil => acc.reverse
case x :: xs if p(x) => (x :: acc).reverse
case x :: xs => loop(x :: acc, xs)
}
loop(List[T](), list)
}
}
}
class TakeUntilInclusiveSpec extends WordSpec with Matchers {
//import TakeUntilInclusiveSpec.TakeUntilInclusiveFoldLeft
import TakeUntilInclusiveSpec.TakeUntilInclusiveTailRec
val `return` = afterWord("return")
object lists {
val one = List(1)
val oneToTen = List(1, 2, 3, 4, 5, 7, 8, 9, 10)
val boat = List("boat")
val rowYourBoat = List("row", "your", "boat")
}
"TakeUntilInclusive" when afterWord("given") {
"an empty list" should `return` {
"an empty list" in {
List[Int]().takeUntilInclusive(_ == 7) shouldBe Nil
List[String]().takeUntilInclusive(_ == "") shouldBe Nil
}
}
"a list without the matching element" should `return` {
"an identical list" in {
lists.one.takeUntilInclusive(_ == 20) shouldBe lists.one
lists.oneToTen.takeUntilInclusive(_ == 20) shouldBe lists.oneToTen
lists.boat.takeUntilInclusive(_.startsWith("a")) shouldBe lists.boat
lists.rowYourBoat.takeUntilInclusive(_.startsWith("a")) shouldBe lists.rowYourBoat
}
}
"a list containing one instance of the matching element in the last index" should `return`
{
"an identical list" in {
lists.one.takeUntilInclusive(_ == 1) shouldBe lists.one
lists.oneToTen.takeUntilInclusive(_ == 10) shouldBe lists.oneToTen
lists.boat.takeUntilInclusive(_ == "boat") shouldBe lists.boat
lists.rowYourBoat.takeUntilInclusive(_ == "boat") shouldBe lists.rowYourBoat
}
}
"a list containing one instance of the matching element" should `return` {
"the elements of the original list, up to and including the match" in {
lists.one.takeUntilInclusive(_ == 1) shouldBe List(1)
lists.oneToTen.takeUntilInclusive(_ == 5) shouldBe List(1,2,3,4,5)
lists.boat.takeUntilInclusive(_ == "boat") shouldBe List("boat")
lists.rowYourBoat.takeUntilInclusive(_ == "your") shouldBe List("row", "your")
}
}
"a list containing multiple instances of the matching element" should `return` {
"the elements of the original list, up to and including only the first match" in {
lists.oneToTen.takeUntilInclusive(_ % 3 == 0) shouldBe List(1,2,3)
lists.rowYourBoat.takeUntilInclusive(_.length == 4) shouldBe List("row", "your")
}
}
}
}

Possible way of doing this:
def takeUntil[A](list:List[A])(predicate: A => Boolean):List[A] =
if(list.isEmpty) Nil
else if(predicate(list.head)) list.head::takeUntil(list.tail)(predicate)
else List(list.head)

You could use following function,
def takeUntil(list: List[Int]): List[Int] = list match {
case x :: xs if (x != 7) => x :: takeUntil(xs)
case x :: xs if (x == 7) => List(x)
case Nil => Nil
}
val list = List(1,4,5,2,3,5,5,7,8,9,2,7,4)
takeUntil(list) //List(1,4,5,2,3,5,5,7)
Tail Recursive version
def takeUntilRec(list: List[Int]): List[Int] = {
#annotation.tailrec
def trf(head: Int, tail: List[Int], res: List[Int]): List[Int] = head match {
case x if (x != 7 && tail != Nil) => trf(tail.head, tail.tail, x :: res)
case x => x :: res
}
trf(list.head, list.tail, Nil).reverse
}

Some ways by use built-in functions:
val list = List(1, 4, 5, 2, 3, 5, 5, 7, 8, 9, 2, 7, 4)
//> list : List[Int] = List(1, 4, 5, 2, 3, 5, 5, 7, 8, 9, 2, 7, 4)
//Using takeWhile with dropWhile
list.takeWhile(_ != 7) ++ list.dropWhile(_ != 7).take(1)
//> res0: List[Int] = List(1, 4, 5, 2, 3, 5, 5, 7)
//Using take with segmentLength
list.take(list.segmentLength(_ != 7, 0) + 1)
//> res1: List[Int] = List(1, 4, 5, 2, 3, 5, 5, 7)
//Using take with indexOf
list.take(list.indexOf(7) + 1)
//> res2: List[Int] = List(1, 4, 5, 2, 3, 5, 5, 7)

Many of the solutions here are not very efficient, because they explore the whole list, rather than stopping early. Here is a short solution using the in-built functions:
def takeUntil[T](c: Iterable[T], f: T => Boolean): Iterable[T] = {
val index = c.indexWhere(f)
if (index == -1) c else c.take(index + 1)
}

Related

How to remove duplicate ints before a certain element in Scala

I have a list that can have certain numbers before an index that I don't need. For example:
val tempList: List[Any] = List(0,0,0,0,0,3,.,5,0,2,5)
How would I be able to remove all of the 0's before 3 without filtering out the 0 after the 3?
You can use dropWhile. Suppose you want to remove everything before 1:
scala> val l = List(0, 0, 0, 0, 1, 2, 0)
l: List[Int] = List(0, 0, 0, 0, 1, 2, 0)
scala> l.dropWhile(_ == 0)
res1: List[Int] = List(1, 2, 0)
What you need to do is a twist on dropWhile, that I would call filterWhile.
One simple solution that leverages the Collection API is the following:
def filterWhile[A](
list: List[A]
)(filterP: A => Boolean, whileP: A => Boolean): List[A] = {
val (toFilter, unfiltered) = list.span(whileP)
toFilter.filter(filterP) ++ unfiltered
}
You can play around with this code here on Scastie, alongside a couple of tests to verify it works as expected, which are the following:
def test[A](
input: List[A],
expected: List[A]
)(filterP: A => Boolean, whileP: A => Boolean): Unit =
assert(
filterWhile(input)(filterP, whileP) == expected,
s"input: $input, expected: $expected, got: ${filterWhile(input)(filterP, whileP)}"
)
test(
input = List(0, 0, 0, 0, 0, 3, '.', 5, 0, 2, 5),
expected = List(3, '.', 5, 0, 2, 5)
)(filterP = _ != 0, whileP = _ != 3)
test(
input = List(0, 0, 0, 1, 0, 3, '.', 5, 0, 2, 5),
expected = List(1, 3, '.', 5, 0, 2, 5)
)(filterP = _ != 0, whileP = _ != 3)
test(
input = List(1, 2, 3, 4),
expected = List(1, 2, 3, 4)
)(filterP = _ < 5, whileP = _ < 5)
In your case in particular all you have to do is invoke the function as follows:
filterWhile(tempList)(_ != 0, _ != 3)
Where the first predicate says how to filter and the second defines the "while" clause. I chose to align the predicate ordering to the name of the function (it first says "filter" and then "while") but feel free to adjust according to your preference. In any case, using named parameters is probably a good thing here.
Combining existing functions on lists, I came up with:
def filterUntil[A](list: List[A], filter: A => Boolean, cond: A => Boolean): List[A] = {
list.takeWhile(cond).filter(filter) ++ list.dropWhile(cond)
}
This produces much the same results as #stefanobaghino's answer.
This might be done with a foldLeft but in this case I would got for a recursive routine:
def remove(list: List[Any]): List[Any] = {
def loop(rem: List[Any], res: List[Any]): List[Any] =
rem match {
case Nil =>
res
case 0 :: tail =>
loop(tail, res)
case 3 :: _ =>
res ++ rem
case x :: tail =>
loop(tail, res :+ x)
}
loop(list, Nil)
}
remove(List(0,0,0,0,0,3,".",5,0,2,5))
// List(3, ., 5, 0, 2, 5)
Note that this won't be efficient for long lists because adding to the tail of a List gets very slow with longs lists.
Also, as noted in the comments, you should avoid Any if possible and use a more specific type.
[ Simplifications thanks to #MikhailIonkin ]

Group elements in a list by range Scala

Considering the following List in Scala :
List(4, 5, 6, 7, 8, 12, 13, 14, 17, 23, 24, 25)
I want to get the output
List(List(4,8), List(12,14), List(17), List(23,25))
I have this answer Scala List function for grouping consecutive identical elements
But it is working for grouping identical elements in the same List.
How to extend this solution to resolve my current problem?
I have tried this code
def sliceByRange[A <% Int](s: List[A]): List[List[A]] = s match {
case Nil => Nil
case x :: xs1 =
val (first, rest) = s.span(y => y - x == 1)
first :: sliceByRange(rest)
}
But it is not working.
Tail-recursive solution
Code
Note that you could also use List[(Int,Int)] as result type instead of List[List[Int]]. This would reflect the fact that the result is a List of ranges more appropriately. Of course then you couldn't turn List(x,x) into List(x) for singleton ranges. But I expect that this will come back to bite you later anyway.
import scala.annotation.tailrec
#tailrec
def split(in: List[Int], acc: List[List[Int]] = Nil): List[List[Int]] = (in,acc) match {
case (Nil,a) => a.map(_.reverse).reverse
case (n :: tail, (last :: t) :: tt) if n == last + 1 => split(tail, (n :: t) :: tt)
case (n :: tail, a ) => split(tail, (n :: n :: Nil) :: a)
}
val result = split(List(4, 5, 6, 7, 8, 12, 13, 14, 17, 23, 24, 25))
println(result)
println("removing duplicates:")
println(result.map{
case List(x,y) if x == y => List(x)
case l => l
})
Output
List(List(4, 8), List(12, 14), List(17, 17), List(23, 25))
removing duplicates:
List(List(4, 8), List(12, 14), List(17), List(23, 25))
Here is another example:
val myList = List(4, 5, 7, 8, 12, 13, 14, 17, 23, 24, 25)
def partition(list: List[Int]): (List[Int], List[Int]) = {
val listPlusOne = (list.head - 1 :: list) // List(1,2,5) => List(0, 1, 2, 5)
val zipped = list zip listPlusOne // zip List(1,2,5) with List(0, 1, 2, 5) => List((1,0), (2,1), (5,2))
val (a, b) = zipped span { case (a, b) => b + 1 == a } // (List((1,0), (2,1)), List((5,2)))
(a.map(_._1), b.map(_._1)) // (List(1, 2),List(5))
}
def group(list: List[Int]): List[List[Int]] = list match {
case Nil => Nil
case _ =>
val (a, b) = partition(list)
val listA = List(List(a.head, a.last).distinct) // remove middle numbers..
val listB = if (b.isEmpty) Nil else group(b)
listA ++ listB
}
println(group(myList))
A bit more complicated, but it works...
Paraphrasing the answer of the question you referenced:
def split(list: List[Int]) : List[List[Int]] = list match {
case Nil => Nil
case h::t =>
val segment = list.zipWithIndex.takeWhile { case (v, i) => v == h+i }.map(_._1)
List(h, segment.last).distinct :: split(list drop segment.length)
}
Using zipWithIndex to check for each element whether it's exactly the "next" integer (number should increase "together" with the index). Then - taking only the "boundaries" of the segment and recursively moving on to the rest of the list.
My solution:
def sliceByRange(items: List[Int]) =
items.sorted.foldLeft(Nil: List[List[Int]]) {
case (initRanges :+ (head :: Nil), next) if head == next - 1 =>
initRanges :+ (head :: next :: Nil) // append element to the last range
case (initRanges :+ (head :: last :: Nil), next) if last == next - 1 =>
initRanges :+ (head :: next :: Nil) // replace last range
case (ranges, next) =>
ranges :+ (next :: Nil) // add new range
}
Usage:
sliceByRange(List(1, 2, 3, 5, 8, 9, 12, 13, 14, 19))
// List(List(1, 3), List(5), List(8, 9), List(12, 14), List(19))
If you wish to keep middle values you can use the following example:
def makeSegments(items: List[Int]) =
items.sorted.foldLeft(Nil: List[List[Int]]) {
case (initSegments :+ lastSegment, next) if lastSegment.last == next - 1 =>
initSegments :+ (lastSegment :+ next)
case (segments, next) =>
segments :+ (next :: Nil)
}
Usage:
makeSegments(List(1, 2, 3, 5, 8, 9, 12, 13, 14, 19))
// List(List(1, 2, 3), List(5), List(8, 9), List(12, 13, 14), List(19))
When range size at least 3 elements:
def sliceByRange3elements(items: List[Int]) =
items.sorted.foldLeft(Nil: List[List[Int]]) {
case (initRanges :+ (head :: last :: Nil), next) if last == next - 1 =>
initRanges :+ (head :: next :: Nil) // replace last range
case (initRanges :+ (ll :: Nil) :+ (l :: Nil), next) if ll == next - 2 && l == next - 1 =>
initRanges :+ (ll :: next :: Nil) // make new range
case (ranges, next) =>
ranges :+ (next :: Nil)
}
Usage (note that (8,9) are not range now):
sliceByRange3elements(List(1, 2, 3, 5, 8, 9, 12, 13, 14, 19))
// List(List(1, 3), List(5), List(8), List(9), List(12, 14), List(19))
You can define printRanges method to more visual output:
def printRanges(ranges: List[List[Int]]) =
ranges.map({
case head :: Nil => head.toString
case head :: last :: Nil => s"$head-$last"
case _ => ""
}).mkString(",")
printRanges(
sliceByRange(List(1, 2, 3, 5, 8, 9, 12, 13, 14, 19)))
// 1-3,5,8-9,12-14,19
printRanges(
sliceByRange3elements(List(1, 2, 3, 5, 8, 9, 12, 13, 14, 19)))
// 1-3,5,8,9,12-14,19

Built-in method for rolling Scala List or Seq

I'm trying to roll a list, for example like so:
val notRolled = (1 to 5).toList // List(1,2,3,4,5)
val rolledBy1 = rollList(notRolled,1) // List(2,3,4,5,1)
val rolledBy2 = rollList(notRolled,2) // List(3,4,5,1,2)
val rolledBy3 = rollList(notRolled,3) // List(4,5,1,2,3)
val rolledBy4 = rollList(notRolled,4) // List(5,1,2,3,4)
val rolledBy5 = rollList(notRolled,5) // List(1,2,3,4,5)
val rolledByM1 = rollList(notRolled,-1) // List(5,1,2,3,4)
val rolledByM2 = rollList(notRolled,-2) // List(4,5,1,2,3)
val rolledByM3 = rollList(notRolled,-3) // List(3,4,5,1,2)
val rolledByM4 = rollList(notRolled,-4) // List(2,3,4,5,1)
val rolledByM5 = rollList(notRolled,-5) // List(1,2,3,4,5)
I had a look at scala-lang.org and can't seem to find anything that matches my requirement.
Is there a built-in method for rolling a list?
If not, is there a more efficient way to do it than this:
def rollList[T](theList: List[T], itemsToRoll: Int): List[T] = {
val split = {
if (itemsToRoll < 0) (theList.size + itemsToRoll % theList.size)
else itemsToRoll % theList.size
}
val (beginning, end) = theList.splitAt(split)
end ::: beginning
}
Using the enrich-my-library pattern will allow you to add the roll method directly to all the collections so that you can call myList.roll(2), as opposed to roll(myList, 1).
Using the generic CanBuildFrom pattern allows you to make roll return the best possible type on these collections (so that roll on a List will return a List, but roll on an Iterable will return an Iterable).
All together, here is one option that abides by these patterns:
import scala.collection.generic.CanBuildFrom
import scala.collection.TraversableLike
implicit class TraversableWithRoll[A, Repr <: Traversable[A]](val xs: TraversableLike[A, Repr]) extends AnyVal {
def roll[That](by: Int)(implicit bf: CanBuildFrom[Repr, A, That]): That = {
val builder = bf()
val size = xs.size
builder.sizeHint(xs)
val leftBy = if (size == 0) 0 else ((by % size) + size) % size
builder ++= xs.drop(leftBy)
builder ++= xs.take(leftBy)
builder.result
}
}
This allows you to do some of the following:
List(1, 2, 3, 4, 5).roll(2) //List(4,5,1,2,3)
Seq(3, 4, 5).roll(-1) //Seq(5, 3, 4)
Notice the benefits of the fluent syntax enabled by the enrich-my-library pattern, and the stronger types enabled by the use of the CanBuildFrom implicit .
def rotate[A] (list: List[A], by: Int) = {
if (list.isEmpty) list
else {
val shift = (by % list.size + list.size) % list.size
val (l, r) = list.splitAt(shift)
r ++ l
}
}
val list = List(1, 2, 3, 4, 5)
rotate(list, 1) // List(2, 3, 4, 5, 1)
rotate(list, 2) // List(3, 4, 5, 1, 2)
rotate(list, -1) // List(5, 1, 2, 3, 4)
rotate(list, -2) // List(4, 5, 1, 2, 3)
rotate(list, -9) // List(2, 3, 4, 5, 1)
Here is one way of simulating a circular list in a functional way. I made it so that a positive i will do a right shift and a negative a left shift. This is the reverse of what the question has, but I felt it's more natural.
def shift[T](c: List[T], i: Int) = {
if(c.isEmpty) c
else {
val (h,t) = if (i >= 0) c.splitAt(c.size - i%c.size)
else c.splitAt(- i%c.size)
t ++ h
}
}
Here are some examples in the REPL:
cala> shift(List(1,2,4), 1)
res: List[Int] = List(4, 1, 2)
scala> shift(List(1,2,4), 2)
res: List[Int] = List(2, 4, 1)
scala> shift(List(1,2,4), 3)
res: List[Int] = List(1, 2, 4)
scala> shift(List(1,2,4), 4)
res: List[Int] = List(4, 1, 2)
scala> shift(List(1,2,4), 5)
res: List[Int] = List(2, 4, 1)
scala> shift(List(1,2,4), 6)
res: List[Int] = List(1, 2, 4)
scala> shift(List(1,2,4), -1)
res60: List[Int] = List(2, 4, 1)
scala> shift(List(1,2,4), -2)
res: List[Int] = List(4, 1, 2)
scala> shift(List(1,2,4), -3)
res: List[Int] = List(1, 2, 4)
scala> shift(List(1,2,4), -4)
res: List[Int] = List(2, 4, 1)
scala> shift(List(1,2,4), -5)
res: List[Int] = List(4, 1, 2)
scala> shift(List(1,2,4), -6)
res: List[Int] = List(1, 2, 4)
This is my pure functional very simple proposition:
def circ[A]( L: List[A], times: Int ): List[A] = {
if ( times == 0 || L.size < 2 ) L
else circ(L.drop(1) :+ L.head , times-1)
}
val G = List("1a","2b","3c")
println( circ(G,1) ) //List(2b, 3c, 1a)
println( circ(G,2) ) //List(3c, 1a, 2b)
println( circ(G,3) ) //List(1a, 2b, 3c)
println( circ(G,4) ) //List(2b, 3c, 1a)
Added for times < 0 (rolling backwards):
def circ[A]( L: List[A], times: Int ): List[A] = {
if ( times == 0 || L.size < 2 ) L
else if ( times < 0 ) circ(L.reverse,-times).reverse
else circ(L.drop(1) :+ L.head , times-1)
}
Given:
val notRolled = (1 to 5).toList
Let's say we want rotate with shift = 3
val shift = 3
notRolled.zipWithIndex.groupBy(_._2 < shift).values.flatten.map(_._1)
For negative values we should add 5(lists size), so for shift = -3 we will calculate
val shift = -3
notRolled.zipWithIndex.groupBy(_._2 < 2).values.flatten.map(_._1)
I'm going to incorporate the ideas above, about CanBuildFrom, just as soon as I understand Scala better (!), but in the meantime, I had to do precisely this for the sake of writing a Burrows-Wheeler Transform algorithm. Here, with no take() or drop(), and no errors on empty collections (and, yes, side-effecting code):
def roll[A](xs: Traversable[A]): Iterator[Traversable[A]] = {
var front = xs
var back = collection.mutable.Buffer[A]()
Iterator.continually(front ++ back).takeWhile { _ =>
val done = front.isEmpty
if (!done) {
back :+= front.head
front = front.tail
}
!done
}
}

What is an idiomatic Scala way to "remove" one element from an immutable List?

I have a List, which may contain elements that will compare as equal. I would like a similar List, but with one element removed. So from (A, B, C, B, D) I would like to be able to "remove" just one B to get e.g. (A, C, B, D). The order of the elements in the result does not matter.
I have working code, written in a Lisp-inspired way in Scala. Is there a more idiomatic way
to do this?
The context is a card game where two decks of standard cards are in play, so there may
be duplicate cards but still played one at a time.
def removeOne(c: Card, left: List[Card], right: List[Card]): List[Card] = {
if (Nil == right) {
return left
}
if (c == right.head) {
return left ::: right.tail
}
return removeOne(c, right.head :: left, right.tail)
}
def removeCard(c: Card, cards: List[Card]): List[Card] = {
return removeOne(c, Nil, cards)
}
I haven't seen this possibility in the answers above, so:
scala> def remove(num: Int, list: List[Int]) = list diff List(num)
remove: (num: Int,list: List[Int])List[Int]
scala> remove(2,List(1,2,3,4,5))
res2: List[Int] = List(1, 3, 4, 5)
Edit:
scala> remove(2,List(2,2,2))
res0: List[Int] = List(2, 2)
Like a charm :-).
You could use the filterNot method.
val data = "test"
list = List("this", "is", "a", "test")
list.filterNot(elm => elm == data)
You could try this:
scala> val (left,right) = List(1,2,3,2,4).span(_ != 2)
left: List[Int] = List(1)
right: List[Int] = List(2, 3, 2, 4)
scala> left ::: right.tail
res7: List[Int] = List(1, 3, 2, 4)
And as method:
def removeInt(i: Int, li: List[Int]) = {
val (left, right) = li.span(_ != i)
left ::: right.drop(1)
}
Unfortunately, the collections hierarchy got itself into a bit of a mess with - on List. For ArrayBuffer it works just like you might hope:
scala> collection.mutable.ArrayBuffer(1,2,3,2,4) - 2
res0: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 3, 2, 4)
but, sadly, List ended up with a filterNot-style implementation and thus does the "wrong thing" and throws a deprecation warning at you (sensible enough, since it is actually filterNoting):
scala> List(1,2,3,2,4) - 2
warning: there were deprecation warnings; re-run with -deprecation for details
res1: List[Int] = List(1, 3, 4)
So arguably the easiest thing to do is convert List into a collection that does this right, and then convert back again:
import collection.mutable.ArrayBuffer._
scala> ((ArrayBuffer() ++ List(1,2,3,2,4)) - 2).toList
res2: List[Int] = List(1, 3, 2, 4)
Alternatively, you could keep the logic of the code you've got but make the style more idiomatic:
def removeInt(i: Int, li: List[Int]) = {
def removeOne(i: Int, left: List[Int], right: List[Int]): List[Int] = right match {
case r :: rest =>
if (r == i) left.reverse ::: rest
else removeOne(i, r :: left, rest)
case Nil => left.reverse
}
removeOne(i, Nil, li)
}
scala> removeInt(2, List(1,2,3,2,4))
res3: List[Int] = List(1, 3, 2, 4)
def removeAtIdx[T](idx: Int, listToRemoveFrom: List[T]): List[T] = {
assert(listToRemoveFrom.length > idx && idx >= 0)
val (left, _ :: right) = listToRemoveFrom.splitAt(idx)
left ++ right
}
How about
def removeCard(c: Card, cards: List[Card]) = {
val (head, tail) = cards span {c!=}
head :::
(tail match {
case x :: xs => xs
case Nil => Nil
})
}
If you see return, there's something wrong.
// throws a MatchError exception if i isn't found in li
def remove[A](i:A, li:List[A]) = {
val (head,_::tail) = li.span(i != _)
head ::: tail
}
As one possible solutions you can find index of the first suitable element and then remove element at this index:
def removeOne(l: List[Card], c: Card) = l indexOf c match {
case -1 => l
case n => (l take n) ++ (l drop (n + 1))
}
Just another thought on how to do this using a fold:
def remove[A](item : A, lst : List[A]) : List[A] = {
lst.:\[List[A]](Nil)((lst, lstItem) =>
if (lstItem == item) lst else lstItem::lst )
}
Generic Tail Recursion Solution:
def removeElement[T](list: List[T], ele: T): List[T] = {
#tailrec
def removeElementHelper(list: List[T],
accumList: List[T] = List[T]()): List[T] = {
if (list.length == 1) {
if (list.head == ele) accumList.reverse
else accumList.reverse ::: list
} else {
list match {
case head :: tail if (head != ele) =>
removeElementHelper(tail, head :: accumList)
case head :: tail if (head == ele) => (accumList.reverse ::: tail)
case _ => accumList
}
}
}
removeElementHelper(list)
}
val list : Array[Int] = Array(6, 5, 3, 1, 8, 7, 2)
val test2 = list.splitAt(list.length / 2)._2
val res = test2.patch(1, Nil, 1)
object HelloWorld {
def main(args: Array[String]) {
var months: List[String] = List("December","November","October","September","August", "July","June","May","April","March","February","January")
println("Deleting the reverse list one by one")
var i = 0
while (i < (months.length)){
println("Deleting "+months.apply(i))
months = (months.drop(1))
}
println(months)
}
}

Replacing every occurrence of some element by some other element

What is the best Scala way to replace from some list every occurrence of element x by some other element y? This is what I am doing right now:
list map {
case `x` => y
case a => a
}
Is there more concise way available? Thanks.
list.map(i => if (i==x) y else i)
how about this?
If you need to do this a lot, you might write a utility function:
def replace[T](x: T, y: T) = (i: T) => if (i == x) y else i
This would allow you to write
list map replace(x, y)
Or, for infix syntax:
class ReplaceWith[T](x: T) {
def replaceWith(y: T) = (i: T) => if (i == x) y else i
}
object ReplaceWith {
implicit def any2replaceWith[T](x: T) = new ReplaceWith(x)
}
// now you can write
list map (x replaceWith y)
Another solution is to use a Map:
list map Map(x -> y).withDefault(identity)
With a utility function:
scala> def replace[T](pairs: (T, T)*) = Map(pairs: _*).withDefault(identity)
replace: [T](pairs: (T, T)*)scala.collection.immutable.Map[T,T]
scala> List(1,2,3) map replace(1 -> -1, 3 -> 4)
res0: List[Int] = List(-1, 2, 4)
You can create custom method for replacing:
class RichIterable[E] (col: Iterable[E]) {
def replace(pairs: (E, E)*): Iterable[E] = col map {
a => pairs.find(_._1 == a) match {
case None => a
case Some(p) => p._2
}
}
}
object RichIterable {
implicit def iterable2RichIterable[A](col: Iterable[A]) =
new RichIterable(col)
}
Replacing elements should then be easy:
scala> import RichIterable._
import RichIterable._
scala> List(1, 2, 3, 4, 5, 4, 3, 4, 7).replace(3 -> 30, 4 -> 40)
res1: Iterable[Int] = List(1, 2, 30, 40, 5, 40, 30, 40, 7)