简体   繁体   中英

Scala filter tuples (x, y) == (y, x)

I have a list of tuples, for example:

  (0,2)
  (0,5)
  (2,0)
  (2,5)
  (3,4)
  (4,3)
  (5,0)
  (5,2)

There are some tuples where (x, y) == (y, x) , for example (5, 0) and (0, 5). I want to leave just one of them, for example first one. How can I do it?

Using foldLeft

var ts = List((0,2),  (0,5),  (2,0), (2,5),  (3,4), (4,3), (5,0), (5,2))  

ts.foldLeft(List[(Int,Int)]())
   {(acc, el) => if ((acc contains el) || (acc contains el.swap)) acc else el::acc}
// List[(Int, Int)] = List((3,4), (2,5), (0,5), (0,2))

Or, with Sets for an O(n) version (assuming Set lookup and additions are O(1))

ts.foldLeft(Set[(Int,Int)]()){(acc, el) => if (acc(el.swap)) acc else acc + el}

If it doesn't matter if we re-order ones where the swapped tuple is not present (I'm guessing it doesn't as you don't specify which of the ones that have a swapped tuple should be kept):

ts.map{t => if (t._1 < t._2) t else t.swap}.distinct
// List[(Int, Int)] = List((0,2), (0,5), (2,5), (3,4))

You can groupBy the tuples represented as a Set , which will make Set(0, 5) == Set(5, 0) , etc. Then map the resulting Map to the groups of tuples and convert it back to a List , and finally grab the head of each list for one representative of the group. Calling head is ok here, because the groups will never be empty (they would otherwise just not be there at all).

val list = List((0,2), (0,5), (2,0), (2,5), (3,4), (4,3), (5,0), (5,2))

list.groupBy { case (x, y) => Set(x, y) } // Map[Set, List[(Set, (Int, Int))]]
    .map(_._2)                            // Iterable[List[(Int, Int)]] 
    .toList                               // List[List[(Int, Int)]]
    .map(_.head)                          // List[(Int, Int)]


res10: List[(Int, Int)] = List((0,5), (3,4), (2,5), (0,2))

How about first sorting the tuple pairs internally. I believe this technique would pass through your list just twice since distinct is advertised as O(n) complexity:

val ts = List((0,2),(0,5),(2,0),(2,5),(3,4),(4,3),(5,0),(5,2))

ts.map{ case (x,y) if x < y => (y,x) case (x,y) => (x,y) }.distinct

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM