Method that add and remove an element from a List - list

i'm writing a method that take a list: List[(String, Int)] , x:(String, Int) and a n: Int parameters and return a List[(String, Int)]
The list parameter represents the input list, the x element represents the element to add to the list, the n represents the maximum dimension of the list.
The method has the following behavior:
First of all check if the list has n elements.
If list has
less than n elements, the method add the x elements to the list.
Otherwise if the list contain an elements less than x, the
method remove the minimum element from the list, and add the x
element to the list.
I've implemented the method as the following:
def method(list: List[(String, Int)], x: (String, Int), n: Int) = {
if(list.size < n)
list :+ x
else {
var index = -1
var min = 10000000//some big number
for(el <- 0 to list.size) {
if(list(el)._2 < x._2 && list(el)._2 < min) {
min = list(el)._2
index = el
}
}
if(index != -1) {
val newList = list.drop(index)
newList :+ x
}
else list
}
}
Exist a way to express this behavior in a more clean way??

First, a corrected version of what you posted (but it appears, not what you intended)
def method(list: List[(String, Int)], x: (String, Int), n: Int) = {
if(list.size < n)
list :+ x
else {
var index = -1
for(i <- 0 until list.size) {
val el = list(i)
if(el._2 < x._2)
index = i
}
if(index != -1) {
val (before, after) = list.splitAt(index)
val newList = before ++ after.tail
newList :+ x
}
else list
}
}
And some tests
val l1 = List(("one", 1))
val l2 = method(l1, ("three", 3), 2)
//> l2 : List[(String, Int)] = List((one,1), (three,3))
val l3 = method(l2, ("four", 4), 2)
//> l3 : List[(String, Int)] = List((one,1), (four,4))
val l4 = method(l2, ("zero", 0), 2)
//> l4 : List[(String, Int)] = List((one,1), (three,3))
Neater version (but still not meeting the spec as mentioned in a comment from the OP)
def method(list: List[(String, Int)], x: (String, Int), n: Int) = {
if (list.size < n)
list :+ x
else {
val (before, after) = list.span(_._2 >= x._2)
if (after.isEmpty)
list
else
before ++ after.tail :+ x
}
}
Another version that always removes the minimum, if that's less than x.
def method(list: List[(String, Int)], x: (String, Int), n: Int) = {
if (list.size < n)
list :+ x
else {
val smallest = list.minBy(_._2)
if (smallest._2 < x._2) {
val (before, after) = list.span(_ != smallest)
before ++ after.tail :+ x
} else
list
}
}
and its test results
val l1 = List(("one", 1))
val l2 = method(l1, ("three", 3), 2)
//> l2 : List[(String, Int)] = List((one,1), (three,3))
val l3 = method(l2, ("four", 4), 2)
//> l3 : List[(String, Int)] = List((three,3), (four,4))
val l4 = method(l2, ("zero", 0), 2)
//> l4 : List[(String, Int)] = List((one,1), (three,3))
but as I say in a comment, better to use a method that processes the whole sequence of Xs and returns the top N.

I would separate the ordering from the method itself:
def method[A: Ordering](list: List[A], x: A, n: Int) = ...
What do you want to do if the list contains more than one element less than x? If you're happy with replacing all of them, you could use map rather than your handwritten loop:
list map {
case a if Ordering.lt(a, x) => x
case a => a
}
If you only want to replace the smallest element of the list, maybe it's neater to use min?
val m = list.min
if(m < x) {
val (init, m :: tail) = list.splitAt(list.indexOf(m))
init ::: x :: tail
else list

Related

Scala: slice a list from the first non-zero element

Suppose I have a list filled with zeroes
val a = List(0,0,0,0,2,4,0,6,0,7)
I want to slice away the zeroes preceding the first non-zero element and also return the index where the 1st non-zero element is present.
Foe the above case I want an output:
output = List(2,4,0,6,0,7)
idx = 4
How do I do it?
First, you can use zipWithIndex to conveniently pair each element with its index. Then use dropWhile to return all of the preceding zero elements. From there, you'll have all of the remaining elements paired with their indices from the original List. You can unzip them. Since this may result in an empty list, the index you're looking for should be optional.
scala> val (remaining, indices) = a.zipWithIndex.dropWhile { case (a, i) => a == 0 }.unzip
remaining: List[Int] = List(2, 4, 0, 6, 0, 7) // <--- The list you want
indices: List[Int] = List(4, 5, 6, 7, 8, 9)
scala> val index = indices.headOption
index: Option[Int] = Some(4) // <--- the index of the first non-zero element
This is a use-case for span:
val a = List(0,0,0,0,2,4,0,6,0,7)
val (zeros, output) = a.span(_ == 0)
val idx = zeros.length
use dropWhile:
val output = a.dropWhile{ _ == 0 }
val idx = output.headOption
.map(_ => a.length - output.length)
.getOrElse(-1) // index starting from 0, -1 if not found
Sightly modified from #bottaio answer, but returning an Option[Int] instead of a plain Int for the index.
def firstNonZero(l: List[Int]): (Option[Int], List[Int]) = {
#annotation.tailrec
def go(remaining: List[Int], idx: Int): (Int, List[Int]) =
remaining match {
case Nil => idx -> Nil
case 0 :: xs => go(remaining = xs, idx + 1)
case xs => idx -> xs
}
l match {
case 0 :: xs =>
val (idx, list) = go(remaining = xs, idx = 1)
Some(idx) -> list
case list =>
None -> list
}
}
Just another solution using foldLeft:
val (i, l) =
a.foldLeft((None: Option[Int], List.empty: List[Int]))((b, n) => {
if (n == 0 && b._2.isEmpty) (b._1.orElse(Some(0)).map(_ + 1), List.empty)
else (b._1.orElse(Some(0)), b._2 :+ n)
})
i: Option[Int] = Some(4)
l: List[Int] = List(2, 4, 0, 6, 0, 7)
You can do it pretty clean with indexWhere:
val idx = a.indexWhere(_!=0)
val output = a.drop(idx)
Others have provided answers that requires multiple list traversals. You can write a recursive function to calculate that in a single pass:
def firstNonZero(l: List[Int]): (Int, List[Int]) = {
#tailrec
def go(l: List[Int], idx: Int): (Int, List[Int]) = l match {
case Nil => (idx, Nil)
case 0 :: xs => go(xs, idx + 1)
case xs => (idx, xs)
}
go(l, 0)
}
what is also equivalent to
val (leadingZeros, rest) = a.span(_ == 0)
val (index, output) = (leadingZeros.length, rest)

Scala remove elements from list of tuples

I'm new to scala and I'm trying to remove from a list of tuples elements which their first value is bigger than the second.
For example, From the list:
val list = List[(Int,Int)]((1,3),(3,1),(2,2))
I want to get the list:
val list = List[(Int,Int)]((1,3),(2,2))
So I used the following lines:
var newList = List[(Int, Int)]()
for (element <- list) {
if (element._1 <= element._2) {
newList ::= element;
}
}
But it feels very long for scala.. Is there a shorter way?
Like twillouer's and tzofia's solutions, but with pattern matching:
list filter { case (a, b) => a <= b }
You can simply do:
list.filter(element => element._1 <= element._2)
The filter function filters out elements which do not satisfy the given boolean condition.
you can use filter like this :
scala> val list = List[(Int,Int)]((1,3),(3,1),(2,2))
list: List[(Int, Int)] = List((1,3), (3,1), (2,2))
scala> val newList = list.filter(a => a._1 <= a._2)
newList: List[(Int, Int)] = List((1,3), (2,2))
or filterNot for the example :
scala> val newList = list.filterNot(a => a._1 > a._2)
newList: List[(Int, Int)] = List((1,3), (2,2))

SML: Remove the entry from the List

How can I delete the element elem in list L? If the list does not contain elem, then the function should return the list unchanged.
For instance:
L = [1, 3, 4, 0, 5, 7]
elem = 5
So far I have the following function:
fun removeElem elem myList[] = myList
| removeElem (myList::tl) = if mem myList elem then
rm elem myList[]
else
removeElem elem tl
You can turn the question around and ask how to keep only those items not equal to elem. This fits cleanly with filter:
fun removeElem elem myList = filter (fn x => x <> elem) myList
This code will accomplish what you want to do: remove the element (actually it will remove all instances of the element if there are more than one) and return the rest of the list as-is:
fun remove_element (list, element) =
case list of
[] => []
| list_head::list_tail => let val a = remove_element(list_tail, element)
in
if list_head = element
then a
else list_head::a
end
fun delete (s,[]) = []
| delete (s,x::xs') =
if s = x then xs' (* more efficient than call delete function again *)
else x::delete(s, xs')
fun remove_element (elemlist, elem) =
case elemlist of
[] => []
| head::tail => if elem = head
then remove_element (tail, elem)
else head::remove_element (tail, elem)
Output SML/NJ:
val remove_element = fn : ''a list * ''a -> ''a list
val it = () : unit
(* matching *)
- remove_element ([1,2,3,4,5], 4);
val it = [1,2,3,5] : int list
(* non matching *)
- remove_element ([1,2,3,4,5], 7);
val it = [1,2,3,4,5] : int list
(* multiple instances *)
- remove_element ([1,3,4,4,5],4);
val it = [1,3,5] : int list
With no libraries or extra functions
fun remv(L, c) =
if null(L) then nil
else if c=hd(L) then remv(tl(L), c)
else hd(L)::remv(tl(L), c);
You can try this code.
fun remove_element (elemlist:int list, elem:int) =
case elemlist of
[] => []
| head::tail => if elem = head
then remove_element (tail, elem)
else head::remove_element (tail, elem)
also you can use this function to remove duplicate entries from a list:
fun remove_duplicates(xs: ''a list) =
let
fun helper(ds: ''a list, m: ''a) =
if null ds
then []
else if hd ds = m
then helper(tl ds, m)
else hd ds :: helper(tl ds, m)
in
if null xs
then []
else hd xs :: remove_duplicates( helper(tl xs, hd xs) )
end

Accessing the next element in list to compare in Scala

I'm new to Scala and i was wondering how you can call the next element of the list because I am trying to compare the current element with the adjacent one.
Given x as the current element, I tried similar to java, x+1 but that didnt work. Any help?
for (x <- list; if (x == (next adj. element))) println("same")
How about sliding?
val list = List(1,2,3,4)
list.sliding(2).foreach(println)
//List(1, 2)
//List(2, 3)
//List(3, 4)
The canonical ways to do this in a for loop would be:
scala> val xs = List(1,2,3,4,3,2)
xs: List[Int] = List(1, 2, 3, 4, 3, 2)
scala> for (List(left,right) <- xs.sliding(2) if (left < right)) println(left + " < " + right)
1 < 2
2 < 3
3 < 4
scala> for ((left,right) <- (xs zip xs.tail) if (left < right)) println(left + " < " + right)
1 < 2
2 < 3
3 < 4
(Incidentally, you're probably better off putting the if statement outside rather than inside the for comprehension in this example.)
If you have indices instead of values, you just dereference them using the same pattern. Personally, I don't find this pattern very clear or useful. It's slow, has weird corner-cases with lists that aren't full, and it's hard to follow what's going on. Instead, I define
class PairedIterable[A](it: Iterable[A]) {
def foreachpair(f: (A,A) => Unit) = {
val i = it.iterator
if (i.hasNext) {
var prev = i.next
while (!ans && i.hasNext) {
val x = i.next
f(prev,x)
prev = x
}
}
}
}
implicit def iterable_has_pairs[A](it: Iterable[A]) = new PairedIterable(it)
which can then be used like so:
scala> xs.foreachpair((left, right) => if (left < right) println(left + " < " + right))
1 < 2
2 < 3
3 < 4
Variants "forallpair", "existspair", and "findpair" are particularly useful.
scala> val xs = 1::3::5::4::Nil
xs: List[Int] = List(1, 3, 5, 4)
scala> (xs, xs.tail).zip.foreach(println)
(1,3)
(3,5)
(5,4)
scala>
As an option you may use match and recursion instead of for:
object Test {
def main(args: Array[String]) {
val list = List(1, 5, 3)
loop(list)
}
def loop(list: List[Int]) {
list match {
case Nil => println("Empty list")
case x :: Nil => println("last " + x)
case x :: tail => {
println(x + " - " + tail.head)
loop(tail)
}
}
}
}
This would be better handled by recursing over the list, instead of iterating through the elements, since elements don't know anything about the list.
For example:
def recurse[T](list: List[T]): Unit = list match {
case List(x, y, _*) if x == y =>
println("same")
recurse(list.tail)
case Nil =>
case _ => recurse(list.tail)
}
As in Scala 2.11.7 the following are valid:
scala> val xs = List(1,2,3,4)
xs: List[Int] = List(1, 2, 3, 4)
1) Zip the tail
scala> xs.zip(xs.tail)
res0: List[(Int, Int)] = List((1,2), (2,3), (3,4))
2) Slide the window
scala> xs.sliding(2)
res1: Iterator[List[Int]] = non-empty iterator
list.tail.head
gives the next element if you want to go through all the elements from the front of the list. This is because the head is the front-most element and tail is the rest of the list.
scala> val li = List (3, 4, 5)
li: List[Int] = List(3, 4, 5)
scala> li.tail.head
res74: Int = 4
If you don't want to compare just a single element, but a sequence of arbitrary length, you can do it in recursive function:
def compAdjectent (l: List [Int]) : Boolean = l match {
case Nil => false
case x :: Nil => false
case x :: y :: xs => if (x.equals (y)) true else compAdjectent (y :: xs)
}

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