filtering element of one List from another in Scala with different tuple structure

I am trying to understand the best way to write this. This is part of my organization work so can't disclose it fully here like why such requirement. So Apologies for that.

I have ListA and ListB.

val ListA: List[((String, String), Int)] = List(
(("A", "B"), 1),
(("C", "D"), 2),
(("E", "F"), 5),
(("E", "F"), 4),
(("E", "F"), 3)
)
val ListB: List[(String, String)] = List(
("A", "B"),
("E", "F")
)


We need to search id in ListA that contain ListB element. For example tuple ("A", "B") is present in ListA with (("A", "B"), 1), . so output would be List(1). This process would repeat again once we fetch first match. if no match is found then List(0) would be output. Also both lists are sorted on priority. ListB drives the main priority and after that in case of repeating values the List A does it. And lists are already ordered. I wrote this.

val result = ((for {
a <- ListB
m <- ListA.filter(_._1 == a).map(_._2)
} yield m):::List(0)).slice(0,1)


slice is used because we need List with first match. as ListB is already sorted on priority. Also We are going to repeat this process again by removing already matched id from ListA. But for now please ignore like how we remove these elements and re-iterate.

So new iteration would be on

val ListA: List[((String, String), Int)] = List(
//  (("A", "B"), 1), This will not be part of second iteration as we already matched it in first iteration.
(("C", "D"), 2),
(("E", "F"), 5),
(("E", "F"), 4),
(("E", "F"), 3)
)
val ListB: List[(String, String)] = List(
("A", "B"),
("E", "F")
)


Output of

• iteration 1 is List(1)
• iteration 2 is List(5)
• iteration 3 is List(4)
• iteration 4 is List(3)
• iteration 5 is List(0)

I would just like to understand that

"Is it right way to code where we search one list element in another".

"Do we have some scala library that can be used here like ListA.filter(ListB.contains(_._1)) --> this needs us to write full filter case method so it wont work like this"

• Welcome to CR! Could you explain the reasoning behind the exact way this filtering is supposed to work? I have a hard time seeing why an iterative solution is necessary at all. That's all why we require some review context. As it stands you're providing a very algorithmic explanation of the desired output, with no context as to why that's necessary. Readers might be able to suggest a better way of providing the desired, or an equivalent result, when they can actually know how the algorithm is going to be used in the end. If it's an exercise please provide the exact wording. – ferada Mar 17 at 10:11
• ferada is correct. On this site, we review real, complete, working code. We don't discuss best practices and we don't review stubs or pseudo code (which is what this feels like to me). I guarantee that, as written, this question will get closed, and soon, if it is not brought up to standards. – Donald.McLean Mar 17 at 13:59
• Hey Ferada, the thing is its something related to my organization so I can't disclose use case. Requirements or the use case looks into multiple priorities as both lists are sorted on different level of preferences. I did it using (listB.flatMap(x=> listA.filter(._1 == x).map(._2)) :+ 0).head . – Ashish Mishra Mar 18 at 9:38
• Hey @Donald, I am really sorry if I I have asked question on wrong platform. I would definitely improve on this. I thought we can ask questions on best practices which is present in this reference document. I had gone through codereview.stackexchange.com/help/on-topic – Ashish Mishra Mar 18 at 11:05

Apart from my comment, I'd suggest using Set for, well sets, since operations will likely be quicker, but more importantly, they're more correct wrt. what operations can be done on them.

val setB: Set[(String, String)] = ListB.toSet

val filtered: List[((String, String), Int)] =
ListA.filterNot(x => setB.contains(x._1))

val result: List[Int] =
filtered.map(_._2)


This returns a different result. As I wrote in my comment I don't quite understand the reasoning behind the algorithm and if it's a real requirement that it's going to be iterative like this, you'll likely have to use the implementation you have right now, i.e. via for.

Also splitting the computation into multiple steps might help with understanding what's going on (especially in a debugger), that's also why I copied over the type signatures as you did.

*If the exact same output is desired*, that'd be this then:
val result = ((for {
m <- ListA.filter(x => setB.contains(x._1)).map(_._2)
} yield m):::List(0)).slice(0,1)

Nevermind, the same result requires to walk through the list as in the original post.
• Also variables shouldn't start with an upper case, c.f. setB instead of SetB.
• m <- ListA.filter(x => setB.contains(x._1)).map(_._2), Here if ListB is lets say ( ("E", "F"),("A", "B")).. the answer would still be same but we want order to be taken care of. First priority to ListB and second priority to ListA in case of repeat values. Answer in this case should be like 5,4,3,1,0. I did it using (listB.flatMap(x=> listA.filter(._1 == x).map(._2)) :+ 0).head . – Ashish Mishra Mar 18 at 9:46
• I removed the last section. In that case I don't think there's anything to fix other than making the code less dense and introducing some better variable names. – ferada Mar 18 at 9:54