2015-03-30 89 views
3

說我有一個斯卡拉列表,比較列表的元素對所有其他元素

val list : List[Set[Int]] = List(set1, set2, set3, set4) 

在我的列表中的每個元素是一個整數集。

我在尋找一個優雅的方式來創建一個列表,其中我的列表中的每個元素都與所有其他人進行比較。例如,我可能想要生成一個列表,其中每個元素(集合)只包含未包含在列表的任何其他元素中的元素。

例如我有一些功能:

def f(element : Set[Int], rest_of_list : List[Set[Int]]) : Set[Int] 

,我想要做類似的東西list.map(f(_, rest_of_list))無需構建rest_of_list每個元素。我現在想的唯一辦法就是使用slice,這使得它非常醜陋,效率低下。

回答

2

可以使用diff代替slice

list.map(set => set diff (list diff List(set)).flatten.toSet) 
//Alternative with filterNot 
list.map(set => set.filterNot((list diff List(set)).flatten.contains)) 

diff作品在這裏,因爲它僅刪除元素的一個實例,並Set[Int]有一個很好的equals方法:

List(Set(1), Set(1, 2)) diff List(Set(1)) //List(Set(1, 2)) 
List(Set(1), Set(1)) diff List(Set(1)) //List(Set(1)) 

所以,這將一組圖映射到列表中所有其他組的列表:

val setWithOthers = list.map(set => set -> (list diff List(set))) 
val setWithOthers = (list, list.map(list diff List(_))).zipped.toList //equivalent, less efficient 

所以,如果你想你的映射跨list元素功能f,你可以這樣做:

setsWithOthers.map { case(set, others) => f(set, others) } 
setsWithOthers.map(kvp => f(kvp._1, kvp._2)) 
setsWithOthers.map((f _).tupled) 

您還可以創建完整的多集,其跟蹤的每一個元素出現了多少次。然後,在每次循環,可以從滿多集「減」一組:

val multiset = list.flatten.groupBy(identity).mapValues(_.length) 
+0

這是比使用切片漂亮的數量級,但它仍然不是我所希望的。 (我的失望是針對scala,而不是你的回答) – 2015-03-30 22:48:22

+0

hehe你用我更好的版本更新了我的想法。地圖方法是我接受的答案。 – 2015-03-30 22:58:06

1

我不知道,如果你想它是優雅,但更普遍的方式,你可以更換'f'與任何東西:

val list = List(Set(1,2,3,4),Set(1,2),Set(1,3)) 

list.map(e => f(e,list.filterNot(_==e))) 
//res0: List[Set[Int]] = List(Set(4), Set(), Set()) 

def f(element : Set[Int], rest_of_list : List[Set[Int]]) : Set[Int] = { 
    (element.toList diff rest_of_list.flatten.toList).toSet 
}