get indexes of elements containig some value and the coresponding elements from another list - scala

The queston is a mouthful, but the idea pretty simple.
I have 3 lists and a string.
val a = List("x", "y", "z")
val b = List("a1", "a2", "b1", "b2", "c1", "c2", "d1", "d2")
val c = List("1", "1", "2", "2", "3", "3", "4", "4")
val d = "xc1b1"
I need to check if d contains elements from a. If it does I check the position of all the elemtns from b that are present in d and return a set of elements from c that corespond these positions.
The result for the given example is
Set("3", "2")
But when I try
if(a.exists(d.contains)) c(b.indexWhere(d.contains))
I only get
Any = 2
Which corespond to the first encountered elemnt from b ie b1
How would I get the set?

-
if(a.exists(d.contains)) b.zip(c).collect{
case (x, y) if d.contains(x) => y
}
// res1: Any = List(2, 3)
If you need a Set:
if(a.exists(d.contains)) b.zip(c).collect{
case (x, y) if d.contains(x) => y
}.toSet
// res2: Any = Set(2, 3)

I think I've understood what you need to do here, although the question could do with some clarification.
These are the two ways of getting to your set that I found:
if(a.exists(d.contains)) b.collect {
case x if d.contains(x) => c(b.indexOf(x))
}.toSet
if(a.exists(d.contains)) b.filter(d.contains).map(b.indexOf).map(c).toSet
Both find elements of b that are in d, then find their index in b and find their relative elements in c. The first way is more explicit in what it's doing, while the second way is more concise.

Related

Merging lists in scala

I have to merge these two lists together in a way that results in the 3rd list. I'm not super familiar with Scala that much but I am always interested in learning.
val variable = List("a", "b", "c") | val number = List("1", "2", "3")
When merged and printing each value after, it should result in an output like this
a is equal to 1
b is equal to 2
c is equal to 3
with a list that is now equal to
List("a is equal to 1", "b is equal to 2", "c is equal to 3")
Please help me out
zip and map would work,
variable.zip(number).map {case (str, int) => s"$str is equal to $int"}
Alternativly, you could use for-comprehensions
Welcome to Scala 3.1.1 (17, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
scala> val variable = List("a", "b", "c")
val variable: List[String] = List(a, b, c)
scala> val number = List("1", "2", "3")
val number: List[String] = List(1, 2, 3)
scala> for {
| str <- variable
| n <- number
| } yield s"$str is equal to $n"
val res0: List[String] = List(a is equal to 1, a is equal to 2, a is equal to 3, b is equal to 1, b is equal to 2, b is equal to 3, c is equal to 1, c is equal to 2, c is equal to 3)

Splitting a Scala List into parts using a given list of part sizes.[Partitioning]

I got two lists:
val list1:List[Int] = List(5, 2, 6)
val list2:List[Any] = List("a", "b", "c", "d", "e", "f", "g", "h", "i", "j","k")
such that list1.sum >= list2.size
I want a list of lists formed with elements in list2 consecutively
with the sizes mentioned in list1.
For example:
if list1 is List(5,2,4) the result I want is:
List(List("a", "b", "c", "d", "e"),List("f", "g"),List("h", "i", "j","k"))
if list1 is List(5,4,6) the result I want is:
List(List("a", "b", "c", "d", "e"),List("f", "g","h", "i"),List("j","k"))
How can I do that with concise code.
Turn list2 into an Iterator then map over list1.
val itr = list2.iterator
list1.map(itr.take(_).toList)
//res0: List[List[Any]] = List(List(a, b, c, d, e), List(f, g), List(h, i, j, k))
update:
While this appears to give the desired results, it has been pointed out elsewhere that reusing the iterator is actually unsafe and its behavior is not guaranteed.
With some modifications a safer version can be achieved.
val itr = list2.iterator
list1.map(List.fill(_)(if (itr.hasNext) Some(itr.next) else None).flatten)
-- or --
import util.Try
val itr = list2.iterator
list1.map(List.fill(_)(Try(itr.next).toOption).flatten)
you can slice on list2 based on the size you get from list1,
def main(args: Array[String]): Unit = {
val groupingList: List[Int] = List(5, 2, 4)
val data = List("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k")
//0, 5
//5, (5 + 2)
//5 + 2, (5 + 2 + 4)
val grouped = groupingList.zipWithIndex.map { case (_, index) =>
val start = groupingList.slice(0, index).sum
val end = groupingList.slice(0, index + 1).sum
data.slice(start, end)
}
println(grouped)
}
result: List(List(a, b, c, d, e), List(f, g), List(h, i, j, k))
Also read: How slice works
i like show it using ex
list1=List("one","two","three")
List[String] = List(one, two, three)
list2=List("red","green","blue")
List[String] = List(red, green, blue)
list1::list2
List[java.io.Serializable] = List(List(one, two, three), red, green, blue)
var listSum=list1::list2
List[java.io.Serializable] = List(List(one, two, three), red, green, blue)
listSum
List[java.io.Serializable] = List(List(one, two, three), red, green, blue)
we can "::" for insert one list to another list in Scala
Just found by me, even the following code worked, but the code posted by jwvh appears more concise than this, and I understand making list1 a Vector makes more sense regarding performance of element access in the following code:
list1.scan(0)(_+_).sliding(2).toList.map(x=>list2.drop(x(0)).take(x(1)-x(0)))
or
list1.scan(0)(_+_).zip(list1).map(x=>list2.drop(x._1).take(x._2))
list1.scan(0)(_+_).sliding(2).map(x=>list2.slice(x(0),x(1))).toList

How to insert elements in list from another list using scala?

I have two lists -
A = (("192.168.1.1","private","Linux_server","str1"),
("192.168.1.2","private","Linux_server","str2"))
B = ("A","B")
I want following output
outputList = (("192.168.1.1","private","Linux_server","str1", "A"),
("192.168.1.2","private","Linux_server","str2","B"))
I want to insert second list element into first list as list sequence.
Two lists size will be always same.
How do I get above output using scala??
The short answer:
A = (A zip B).map({ case (x, y) => x :+ y })
Some compiling code to be more explicit:
val a = List(
List("192.168.1.1", "private", "Linux_server", "str1"),
List("192.168.1.2", "private", "Linux_server", "str2")
)
val b = List("A", "B")
val c = List(
List("192.168.1.1", "private", "Linux_server", "str1", "A"),
List("192.168.1.2", "private", "Linux_server", "str2", "B")
)
assert((a zip b).map({ case (x, y) => x :+ y }) == c)

IndexedSeq and removing multiple elements

I have mySeq: IndexedSeq[A] and another myIncludedSeq: IndexedSeq[A], where every element of myIncludedSeq, is contained in mySeq.
I want to create a new IndexedSeq[A] from mySeq without all elements from myIncludedSeq.
I can't find any nice functional approach for this problem. How would you approach it?
Example:
val mySeq = IndexedSeq("a", "b", "a", "c", "d", "a")
val myIncludedSeq = IndexedSeq("a", "d", "a")
//magic
val expectedResult = IndexedSeq("b", "c", "a") //the order does not matter
How about this?
val original = IndexedSeq("a", "b", "a", "c", "d", "a")
val exclude = IndexedSeq("a", "d", "a")
val result = original.diff(exclude)
// IndexedSeq[String] = Vector(b, c, a)
From list's diff doc:
Computes the multiset difference between this list and another sequence.
Returns a new list which contains all elements of this list except
some of occurrences of elements that also appear in "excluding" list. If an
element value x appears n times in that, then the first n occurrences
of x will not form part of the result, but any following occurrences
will.

Proper way for looping in Scala

Suppose I have an array of strings in Scala:
val strings = Array[String]("1", "2", "3", "4", "5", "6", "7")
What I need is to make a new array which elements will be obtained as a concatenation of each three (any number) consequent elements of the first array, which should result in ("123", "456", "7")
Being new to Scala I wrote the following code which was neither concise nor effective:
var step = 3
val strings = Array[String]("1", "2", "3", "4", "5", "6", "7")
val newStrings = collection.mutable.ArrayBuffer.empty[String]
for (i <- 0 until strings.length by step) {
var elem = ""
for (k <- 0 until step if i + k < strings.length) {
elem += strings(i + k)
}
newStrings += elem
}
What would be the Scala way for doing this?
strings.grouped(3).map(_.mkString).toArray
or
strings grouped 3 map (_.mkString) toArray
I personally prefer the first version :)
strings grouped 3 map (_.mkString)
or (in order to really get an Array back)
(strings grouped 3 map (_.mkString)).toArray
... or use sliding
val strings = Array[String]("1", "2", "3", "4", "5", "6", "7")
strings.sliding (3, 3) .map (_.mkString).toArray
res19: Array[String] = Array(123, 456, 7)
Sliding: You take 3, and move forward 3. Variants:
scala> strings.sliding (3, 2) .map (_.mkString).toArray
res20: Array[String] = Array(123, 345, 567)
take 3, but forward 2
scala> strings.sliding (2, 3) .map (_.mkString).toArray
res21: Array[String] = Array(12, 45, 7)
take 2, forward 3 (thereby skipping every third)