Related
I have a Scala list below :
val numList = List(1,2,3,4,5,1,2)
I want to get index of the same element pair in the list. The output should look like (0,5),(1,6)
How can I achieve using map?
def catchDuplicates(num : List[Int]) : (Int , Int) = {
val count = 0;
val emptyMap: HashMap[Int, Int] = HashMap.empty[Int, Int]
for (i <- num)
if (emptyMap.contains(i)) {
emptyMap.put(i, (emptyMap.get(i)) + 1) }
else {
emptyMap.put(i, 1)
}
}
Let's make the challenge a little more interesting.
val numList = List(1,2,3,4,5,1,2,1)
Now the result should be something like (0, 5, 7),(1, 6), which makes it pretty clear that returning one or more tuples is not going to be feasible. Returning a List of List[Int] would make much more sense.
def catchDuplicates(nums: List[Int]): List[List[Int]] =
nums.zipWithIndex //List[(Int,Int)]
.groupMap(_._1)(_._2) //Map[Int,List[Int]]
.values //Iterable[List[Int]]
.filter(_.lengthIs > 1)
.toList //List[List[Int]]
You might also add a .view in order to minimize the number of traversals and intermediate collections created.
def catchDuplicates(nums: List[Int]): List[List[Int]] =
nums.view
.zipWithIndex
.groupMap(_._1)(_._2)
.collect{case (_,vs) if vs.sizeIs > 1 => vs.toList}
.toList
How can I achieve using map?
You can't.
Because you only want to return the indexes of the elements that appear twice; which is a very different kind of transformation than the one that map expects.
You can use foldLeft thought.
object catchDuplicates {
final case class Result[A](elem: A, firstIdx: Int, secondIdx: Int)
private final case class State[A](seenElements: Map[A, Int], duplicates: List[Result[A]]) {
def next(elem: A, idx: Int): State[A] =
seenElements.get(key = elem).fold(
ifEmpty = this.copy(seenElements = this.seenElements + (elem -> idx))
) { firstIdx =>
State(
seenElements = this.seenElements.removed(key = elem),
duplicates = Result(elem, firstIdx, secondIdx = idx) :: this.duplicates
)
}
}
private object State {
def initial[A]: State[A] =
State(
seenElements = Map.empty,
duplicates = List.empty
)
}
def apply[A](data: List[A]): List[Result[A]] =
data.iterator.zipWithIndex.foldLeft(State.initial[A]) {
case (acc, (elem, idx)) =>
acc.next(elem, idx)
}.duplicates // You may add a reverse here if order is important.
}
Which can be used like this:
val numList = List(1,2,3,4,5,1,2)
val result = catchDuplicates(numList)
// result: List[Result] = List(Result(2,1,6), Result(1,0,5))
You can see the code running here.
I think returning tuple is not a good option instead you should try Map like -
object FindIndexOfDupElement extends App {
val numList = List(1, 2, 3, 4, 5, 1, 2)
#tailrec
def findIndex(elems: List[Int], res: Map[Int, List[Int]] = Map.empty, index: Int = 0): Map[Int, List[Int]] = {
elems match {
case head :: rest =>
if (res.get(head).isEmpty) {
findIndex(rest, res ++ Map(head -> (index :: Nil)), index + 1)
} else {
val updatedMap: Map[Int, List[Int]] = res.map {
case (key, indexes) if key == head => (key, (indexes :+ index))
case (key, indexes) => (key, indexes)
}
findIndex(rest, updatedMap, index + 1)
}
case _ => res
}
}
println(findIndex(numList).filter(x => x._2.size > 1))
}
you can clearly see the number(key) and respective index in the map -
HashMap(1 -> List(0, 5), 2 -> List(1, 6))
I am having a hard time understanding m.get and m+(x._1 -> x._2) in below code ,can anyone let me know what does it do
object Solution {
def twoSum(nums: Array[Int], target: Int): Array[Int] = {
nums.zipWithIndex.foldLeft(Map.empty[Int,Int])((m,x)=>
{
if(m.get(target - x._1)==None)
m+(x._1 -> x._2)
else
return Array(m.getOrElse(target-x._1, -1), x._2)
})
null
}
}
This code returns indices of the two numbers such that they add up to a specific target.
Here are a few different (better?) ways to get the same result (essentially the same).
If you want all index pairs whose values sum to the target.
def twoSum(nums :Array[Int], target :Int) :Iterator[Seq[Int]] =
nums.indices
.combinations(2)
.filter{case Seq(a,b) => nums(a) + nums(b) == target}
twoSum(Array(3,5,11,2,13,9), 41) //returns empty Iterator
twoSum(Array(3,5,11,2,13,9), 14) //returns Iterator(Seq(0, 2), Seq(1, 5))
If you want just the first pair that sum to the target (with early termination).
def twoSum(nums :Array[Int], target :Int) :Option[Seq[Int]] =
nums.indices
.combinations(2)
.find{case Seq(a,b) => nums(a) + nums(b) == target}
twoSum(Array(3,5,11,2,13,9), 41) //returns None
twoSum(Array(3,5,11,2,13,9), 14) //returns Some(Seq(0, 2))
If you want to avoid the Option and just return an empty collection if no 2 values sum to the target.
def twoSum(nums :Array[Int], target :Int) :Seq[Int] =
nums.indices
.combinations(2)
.find{case Seq(a,b) => nums(a) + nums(b) == target}
.getOrElse(Seq())
twoSum(Array(3,5,11,2,13,9), 41) //returns Seq()
twoSum(Array(3,5,11,2,13,9), 14) //returns Seq(0, 2)
Here is a more efficient and idiomatic way to solve that problem.
def twoSum(nums: ArraySeq[Int], target: Int): Option[(Int, Int)] = {
val allIndexes = for {
i <- Iterator.range(start = 0, end = nums.length)
j <- Iterator.range(start = i + 1, end = nums.length)
} yield i -> j
allIndexes.find {
case (i, j) => (nums(i) + nums(j)) == target
}
}
(Note: ArraySeq is like any normal array, but it is immutable, it was introduced in 2.13 if you are in an older version, just use a regular Array).
Here is my own take, the function loops through all pairs of numbers until an answer is found. It makes use of scala's optimised recursion capability. Also it uses simple concepts only, useful for beginners: functions, Arrays, Ints and if-else statements.
def twoSum(nums :Array[Int], target : Int): Array[Int] = {
def iter(a:Int, b: Int): Array[Int] = {
if(nums(a) + nums(b) == target) Array(a,b)
else if(b < nums.length-1) iter(a,b+1)
else iter(a+1,a+2)
}
iter(0,1)
}
jwvh: true. with empty array on failure:
def twoSum(nums: Array[Int], target: Int): Array[Int] = {
def iter(a: Int,b: Int): Array[Int] = {
if(nums(a) + nums(b) == target) Array(a,b)
else if(b < nums.length-1) iter(a,b+1)
else if(a < nums.length-2) iter(a+1,a+2)
else Array()
}
iter(0,1)
}
I have a ListBuffer of List[String], val tList = ListBuffer[TCount] where TCount is case class TCount(l: List[String], c: Long). I want to find those list l from tList which are not the subset of any other element of tlist and their c value is less than their superset c value. The following program works but I have to use two for loop that makes the code inefficient. Is there any better approach I can use to make the code efficient?
val _arr = tList.toArray
for (i <- 0 to (_arr.length - 1)) {
val il = _arr(i).l.toSet
val ic = _arr(i).c
for (j <- 0 to (_arr.length - 1)) {
val jl = _arr(j).toSet
val jc = _arr(j).c
if (i != j && il.subsetOf(jl) && ic >= jc) {
tList.-=(_arr(i))
}
}
}
Inspired by the set-trie comment:
import scala.collection.SortedMap
class SetTrie[A](val flag: Boolean, val children: SortedMap[A, SetTrie[A]])(implicit val ord: Ordering[A]) {
def insert(xs: List[A]): SetTrie[A] = xs match {
case Nil => new SetTrie(true, children)
case a :: rest => {
val current = children.getOrElse(a, new SetTrie[A](false, SortedMap.empty))
val inserted = current.insert(rest)
new SetTrie(flag, children + (a -> inserted))
}
}
def containsSuperset(xs: List[A], strict: Boolean): Boolean = xs match {
case Nil => !children.isEmpty || (!strict && flag)
case a :: rest => {
children.get(a).map(_.containsSuperset(rest, strict)).getOrElse(false) ||
children.takeWhile(x => ord.lt(x._1, a)).exists(_._2.containsSuperset(xs, false))
}
}
}
def removeSubsets[A : Ordering](xss: List[List[A]]): List[List[A]] = {
val sorted = xss.map(_.sorted)
val setTrie = sorted.foldLeft(new SetTrie[A](false, SortedMap.empty)) { case (st, xs) => st.insert(xs) }
sorted.filterNot(xs => setTrie.containsSuperset(xs, true))
}
Here is a method that relies on a data structure somewhat similar to Set-Trie, but which stores more subsets explicitly. It provides worse compression, but is faster during lookup:
def findMaximal(lists: List[List[String]]): List[List[String]] = {
import collection.mutable.HashMap
class Node(
var isSubset: Boolean = false,
val children: HashMap[String, Node] = HashMap.empty
) {
def insert(xs: List[String], isSubs: Boolean): Unit = if (xs.isEmpty) {
isSubset |= isSubs
} else {
var isSubsSubs = false || isSubs
for (h :: t <- xs.tails) {
children.getOrElseUpdate(h, new Node()).insert(t, isSubsSubs)
isSubsSubs = true
}
}
def isMaximal(xs: List[String]): Boolean = xs match {
case Nil => children.isEmpty && !isSubset
case h :: t => children(h).isMaximal(t)
}
override def toString: String = {
if (children.isEmpty) "#"
else children.flatMap{
case (k,v) => {
if (v.children.isEmpty) List(k)
else (k + ":") :: v.toString.split("\n").map(" " + _).toList
}
}.mkString("\n")
}
}
val listsWithSorted = for (x <- lists) yield (x, x.sorted)
val root = new Node()
for ((x, s) <- listsWithSorted) root.insert(s, false)
// println(root)
for ((x, s) <- listsWithSorted; if root.isMaximal(s)) yield x
}
Note that I'm allowed to do any kind of mutable nonsense inside the body of the method, because the mutable trie data structure never escapes the scope of the method, and can therefore not be inadvertently shared with another thread.
Here is an example with sets of characters (converted to lists of strings):
println(findMaximal(List(
"ab", "abc", "ac", "abd",
"ade", "efd", "adf", "bafd",
"abd", "fda", "dba", "dbe"
).map(_.toList.map(_.toString))))
The output is:
List(
List(a, b, c),
List(a, d, e),
List(e, f, d),
List(b, a, f, d),
List(d, b, e)
)
so indeed, the non-maximal elements ab, ac, abd, adf, fda and dba are eliminated.
And here is what my not-quite-set-trie data structure looks like (child nodes are indented):
e:
f
b:
e
d:
e
f
c
f
d:
e:
f
f
a:
e
b:
d:
f
c
f
d:
e
f
c
f
c
f
Not sure if you can avoid the complexity, but, I guess I'd write like this:
val tList = List(List(1, 2, 3), List(3, 2, 1), List(9, 4, 7), List(3, 5, 6), List(1, 5, 6), List(6, 1, 5))
val tSet = tList.map(_.toSet)
def result = tSet.filterNot { sub => tSet.count(_.subsetOf(sub)) > 1 }
Here's one approach:
Create an indexed Map for identifying the original List elements
Turn Map of List-elements into Map of Sets (with index)
Generate combinations of the Map elements and use a custom filter to capture the elements that are subset of others
Remove those subset elements from the Map of Sets and retrieve remaining elements from the Map of Lists via the index
Sample code:
type TupIntSet = Tuple2[Int, Set[Int]]
def subsetFilter(ls: List[TupIntSet]): List[TupIntSet] =
if ( ls.size != 2 ) List.empty[TupIntSet] else
if ( ls(0)._2 subsetOf ls(1)._2 ) List[TupIntSet]((ls(0)._1, ls(0)._2)) else
if ( ls(1)._2 subsetOf ls(0)._2 ) List[TupIntSet]((ls(1)._1, ls(1)._2)) else
List.empty[TupIntSet]
val tList = List(List(1,2), List(1,2,3), List(3,4,5), List(5,4,3), List(2,3,4), List(6,7))
val listMap = (Stream from 1).zip(tList).toMap
val setMap = listMap.map{ case (i, l) => (i, l.toSet) }
val tSubsets = setMap.toList.combinations(2).toSet.flatMap(subsetFilter)
val resultList = (setMap.toSet -- tSubsets).map(_._1).map(listMap.getOrElse(_, ""))
// resultList: scala.collection.immutable.Set[java.io.Serializable] =
// Set(List(5, 4, 3), List(2, 3, 4), List(6, 7), List(1, 2, 3))
I am starting the Scala programming course on Coursera, coming from 2 years experience with Java/Python/C#.
I am working through a problem where you must check to see if a list of characters has balanced paranthesis.
/**
* Exercise 2
*/
def balance(chars: List[Char]): Boolean = {
def recursiveBalance(chars: List[Char]): Boolean = {
if (!chars.contains('(') && !chars.contains(')')) true
else {
val openIndex = chars.indexOf('(')
if (openIndex == -1) false
else {
val chars2 = dropFirstMatch(chars, '(')
val closeIndex = chars2.indexOf(')')
if(closeIndex == -1 || openIndex > closeIndex) false
else recursiveBalance(dropFirstMatch(chars2, ')'))
}
}
}
def remove(index: Int, list: List[Char]): List[Char] = {
list.take(index) ++ list.drop(index)
}
def dropFirstMatch[A](ls: List[A], value: A): List[A] = {
val index = ls.indexOf(value) //index is -1 if there is no match
if (index < 0) {
ls
} else if (index == 0) {
ls.tail
} else {
// splitAt keeps the matching element in the second group
val (a, b) = ls.splitAt(index)
a ++ b.tail
}
}
recursiveBalance(chars)
}
So this solution is working (if a little ugly). As part of the solution I attempted to remove an object from a list at a specific index. I've learned that in Scala Lists are immutable.
My attempt at doing this was to provide the index, the list, and use this example, which is the remove function. This works in the REPL, I made a list, ran the function and a new list was returned without the specified index.
But this did not work in my balance solution. Everytime the list was returned it was unchanged, causing infinite recursion. Eventually I stumbled on this article and borrowed their dropFirstMatch function, and upon substituting it, bam, working solution.
I am very new to Scala, and I must be overlooking something - can someone point out what it might be?
take(n) selects the first n elements in your list, where drop(n) selects all elements of the list except the first n ones.
To illustrate:
scala> val xs = List(0,1,2,3,4,5)
xs: List[Int] = List(0, 1, 2, 3, 4, 5)
scala> xs.take(2)
res0: List[Int] = List(0, 1)
scala> xs.drop(2)
res1: List[Int] = List(2, 3, 4, 5)
scala> xs.take(2) ++ xs.drop(2)
res2: List[Int] = List(0, 1, 2, 3, 4, 5)
In other words, your remove function simply returns the same list because it takes the first n elements of the original list, then adds that to the elements of the original list except the first n ones (drop). In order to remove the element at the given index in your list, you merely need to increment the index by one in your call to drop:
def remove(index: Int, list: List[Char]): List[Char] = {
list.take(index) ++ list.drop(index+1)
}
Checking for balanced parenthesis is way easier than what you are doing:
def balanced(list: Seq[Char]): Boolean = list.foldLeft(0) {
case (n, _) if (n < 0) => return false
case (n, '(') => n + 1
case (n, ')') => n - 1
case (n, _) => n
} == 0
Or, if you are a purist, like some commenters, and insist on recursion:
#tailrec
def balanced(chars: Seq[Char], n: Int = 0): Boolean = (n, chars) match {
case (-1, _) => false
case (n, Nil) => n == 0
case ('(' :: tail, n) => balanced(tail, n+1)
case (')' :: tail, n) => balanced(tail, n-1)
case (_ :: tail, n) => balanced(tail, n)
}
I think this might be a common operation. So maybe it's inside the API but I can't find it. Also I'm interested in an efficient functional/simple solution if not.
Given a sequence of tuples ("a" -> 1, "b" ->2, "c" -> 3) I want to turn it into a map. That's easy using TraversableOnce.toMap. But I want to fail this construction if the resulting map "would contain a contradiction", i.e. different values assigned to the same key. Like in the sequence ("a" -> 1, "a" -> 2). But duplicates shall be allowed.
Currently I have this (very imperative) code:
def buildMap[A,B](in: TraversableOnce[(A,B)]): Option[Map[A,B]] = {
val map = new HashMap[A,B]
val it = in.toIterator
var fail = false
while(it.hasNext){
val next = it.next()
val old = map.put(next._1, next._2)
fail = old.isDefined && old.get != next._2
}
if(fail) None else Some(map.toMap)
}
Side Question
Is the final toMap really necessary? I get a type error when omitting it, but I think it should work. The implementation of toMap constructs a new map which I want to avoid.
As always when working with Seq[A] the optimal solution performance-wise depends on the concrete collection type.
A general but not very efficient solution would be to fold over an Option[Map[A,B]]:
def optMap[A,B](in: Iterable[(A,B)]): Option[Map[A,B]] =
in.iterator.foldLeft(Option(Map[A,B]())) {
case (Some(m),e # (k,v)) if m.getOrElse(k, v) == v => Some(m + e)
case _ => None
}
If you restrict yourself to using List[A,B]s an optimized version would be:
#tailrec
def rmap[A,B](in: List[(A,B)], out: Map[A,B] = Map[A,B]()): Option[Map[A,B]] = in match {
case (e # (k,v)) :: tail if out.getOrElse(k,v) == v =>
rmap(tail, out + e)
case Nil =>
Some(out)
case _ => None
}
Additionally a less idiomatic version using mutable maps could be implemented like this:
def mmap[A,B](in: Iterable[(A,B)]): Option[Map[A,B]] = {
val dest = collection.mutable.Map[A,B]()
for (e # (k,v) <- in) {
if (dest.getOrElse(k, v) != v) return None
dest += e
}
Some(dest.toMap)
}
Here is a fail-slowly solution (if creating the entire map and then discarding it is okay):
def uniqueMap[A,B](s: Seq[(A,B)]) = {
val m = s.toMap
if (m.size == s.length) Some(s) else None
}
Here is a mutable fail-fast solution (bail out as soon as the error is detected):
def uniqueMap[A,B](s: Seq[(A,B)]) = {
val h = new collection.mutable.HashMap[A,B]
val i = s.iterator.takeWhile(x => !(h contains x._1)).foreach(h += _)
if (h.size == s.length) Some(h) else None
}
And here's an immutable fail-fast solution:
def uniqueMap[A,B](s: Seq[(A,B)]) = {
def mapUniquely(i: Iterator[(A,B)], m: Map[A,B]): Option[Map[A,B]] = {
if (i.hasNext) {
val j = i.next
if (m contains j._1) None
else mapUniquely(i, m + j)
}
else Some(m)
}
mapUniquely(s.iterator, Map[A,B]())
}
Edit: and here's a solution using put for speed (hopefully):
def uniqueMap[A,B](s: Seq[(A,B)]) = {
val h = new collection.mutable.HashMap[A,B]
val okay = s.iterator.forall(x => {
val y = (h put (x._1,x._2))
y.isEmpty || y.get == x._2
})
if (okay) Some(h) else None
}
Edit: now tested, and it's ~2x as fast on input that works (returns true) than Moritz' or my straightforward solution.
Scala 2.9 is near, so why not to take advantage of the combinations method (inspired by Moritz's answer):
def optMap[A,B](in: List[(A,B)]) = {
if (in.combinations(2).exists {
case List((a,b),(c,d)) => a == c && b != d
case _ => false
}) None else Some(in.toMap)
}
scala> val in = List(1->1,2->3,3->4,4->5,2->3)
in: List[(Int, Int)] = List((1,1), (2,3), (3,4), (4,5), (2,3))
scala> optMap(in)
res29: Option[scala.collection.immutable.Map[Int,Int]] = Some(Map(1 -> 1, 2 -> 3, 3 -> 4, 4 -> 5))
scala> val in = List(1->1,2->3,3->4,4->5,2->3,1->2)
in: List[(Int, Int)] = List((1,1), (2,3), (3,4), (4,5), (2,3), (1,2))
scala> optMap(in)
res30: Option[scala.collection.immutable.Map[Int,Int]] = None
You can also use gourpBy as follows:
val pList = List(1 -> "a", 1 -> "b", 2 -> "c", 3 -> "d")
def optMap[A,B](in: Iterable[(A,B)]): Option[Map[A,B]] = {
Option(in.groupBy(_._1).map{case(_, list) => if(list.size > 1) return None else list.head})
}
println(optMap(pList))
It's efficiency is competitive to the above solutions.
In fact if you examine the gourpBy implementation you will see that it is very similar to some of the solutions suggested.