Scala 按集过滤
Scala filter by set
假设我有一张看起来像这样的地图
val map = Map("Shoes" -> 1, "heels" -> 2, "sneakers" -> 3, "dress" -> 4, "jeans" -> 5, "boyfriend jeans" -> 6)
而且我还有一个像这样的集合:
val set = Array(Array("Shoes", "heels", "sneakers"), Array("dress", "maxi dress"), Array("jeans", "boyfriend jeans", "destroyed jeans"))
我想对我的地图执行过滤操作,以便在我的每个集合中只保留一个元素。预期输出应该是这样的:
map = Map("Shoes" -> 1, "dress" -> 4 ,"jeans" -> 5)
这样做的目的是,如果我有多组表示不同类别的服装,我的输出地图本身不会 "repeat" 在技术上相同的对象上。
感谢任何帮助,谢谢!
所以首先摆脱你的集合实际上是数组的混淆。对于示例的其余部分,我将改用此定义:
val arrays = Array(Array("Shoes", "heels", "sneakers"), Array("dress", "maxi dress"), Array("jeans", "boyfriend jeans", "destroyed jeans"))
所以从某种意义上说,您有一个由等效对象组成的数组,并且想要删除其中一个以外的所有对象?
首先,您必须找到数组中的哪些元素实际用作 mep 中的键。所以我们只是过滤掉所有不用作键的元素:
array.filter(map.keySet)
现在,我们必须选择一个元素。正如你所说,我们只拿第一个:
array.filter(map.keySet).head
由于您的 "sets" 实际上是数组,因此这实际上是数组中第一个也用作键的元素。如果你真的使用集合,这段代码仍然可以工作,因为集合实际上有一个 "first element"。它只是高度特定于实现,甚至可能无法确定同一程序的各种执行。至少对于不可变集,它应该在多次调用 head 时是确定性的,即,你应该总是得到相同的元素。
我们实际上对所有其他元素感兴趣,而不是第一个元素,因为我们想从地图中删除它们:
array.filter(map.keySet).tail
现在,我们只需要从地图中删除它们:
map -- array.filter(map.keySet).tail
并对所有数组执行此操作:
map -- arrays.flatMap(_.filter(map.keySet).tail)
只要数组不相连就可以正常工作。如果不是,我们就不能在每一步都使用初始映射来过滤数组。相反,我们必须使用一个数组来计算一个新地图,然后从上一个的结果开始获取下一个,依此类推。幸运的是,我们不需要做太多事情:
arrays.foldLeft(map){(m,a) => m -- a.filter(m.keySet).tail}
注意:集合也是从元素到布尔值的函数,这就是此解决方案有效的原因。
基本思路是使用groupBy
。像
map.groupBy{ case (k,v) => g(k) }.
map{ case (_, kvs) => kvs.head }
这是对相似事物进行分组的一般方法(使用某些函数 g
)。现在的问题是如何制作您需要的 g
。一种方法是
val g = set.zipWithIndex.
flatMap{ case (a, i) => a.map(x => x -> i) }.
toMap
用数字标记每组,然后形成地图以便您查找。地图有应用功能,所以你可以像上面那样使用它。
这段代码解决了问题:
var newMap = map
set.foreach { list =>
var remove = false
list.foreach { _key =>
if (remove) {
newMap -= _key
}
if (newMap.contains(_key)) {
remove = true
}
}
}
I'm completely new at Scala. I have taken this as my first Scala
example, please any hints from Scala's Gurus is welcome.
稍微简单一点的版本
set.flatMap(_.find(map.contains).map(y => y -> map(y)))
假设我有一张看起来像这样的地图
val map = Map("Shoes" -> 1, "heels" -> 2, "sneakers" -> 3, "dress" -> 4, "jeans" -> 5, "boyfriend jeans" -> 6)
而且我还有一个像这样的集合:
val set = Array(Array("Shoes", "heels", "sneakers"), Array("dress", "maxi dress"), Array("jeans", "boyfriend jeans", "destroyed jeans"))
我想对我的地图执行过滤操作,以便在我的每个集合中只保留一个元素。预期输出应该是这样的:
map = Map("Shoes" -> 1, "dress" -> 4 ,"jeans" -> 5)
这样做的目的是,如果我有多组表示不同类别的服装,我的输出地图本身不会 "repeat" 在技术上相同的对象上。
感谢任何帮助,谢谢!
所以首先摆脱你的集合实际上是数组的混淆。对于示例的其余部分,我将改用此定义:
val arrays = Array(Array("Shoes", "heels", "sneakers"), Array("dress", "maxi dress"), Array("jeans", "boyfriend jeans", "destroyed jeans"))
所以从某种意义上说,您有一个由等效对象组成的数组,并且想要删除其中一个以外的所有对象?
首先,您必须找到数组中的哪些元素实际用作 mep 中的键。所以我们只是过滤掉所有不用作键的元素:
array.filter(map.keySet)
现在,我们必须选择一个元素。正如你所说,我们只拿第一个:
array.filter(map.keySet).head
由于您的 "sets" 实际上是数组,因此这实际上是数组中第一个也用作键的元素。如果你真的使用集合,这段代码仍然可以工作,因为集合实际上有一个 "first element"。它只是高度特定于实现,甚至可能无法确定同一程序的各种执行。至少对于不可变集,它应该在多次调用 head 时是确定性的,即,你应该总是得到相同的元素。
我们实际上对所有其他元素感兴趣,而不是第一个元素,因为我们想从地图中删除它们:
array.filter(map.keySet).tail
现在,我们只需要从地图中删除它们:
map -- array.filter(map.keySet).tail
并对所有数组执行此操作:
map -- arrays.flatMap(_.filter(map.keySet).tail)
只要数组不相连就可以正常工作。如果不是,我们就不能在每一步都使用初始映射来过滤数组。相反,我们必须使用一个数组来计算一个新地图,然后从上一个的结果开始获取下一个,依此类推。幸运的是,我们不需要做太多事情:
arrays.foldLeft(map){(m,a) => m -- a.filter(m.keySet).tail}
注意:集合也是从元素到布尔值的函数,这就是此解决方案有效的原因。
基本思路是使用groupBy
。像
map.groupBy{ case (k,v) => g(k) }.
map{ case (_, kvs) => kvs.head }
这是对相似事物进行分组的一般方法(使用某些函数 g
)。现在的问题是如何制作您需要的 g
。一种方法是
val g = set.zipWithIndex.
flatMap{ case (a, i) => a.map(x => x -> i) }.
toMap
用数字标记每组,然后形成地图以便您查找。地图有应用功能,所以你可以像上面那样使用它。
这段代码解决了问题:
var newMap = map
set.foreach { list =>
var remove = false
list.foreach { _key =>
if (remove) {
newMap -= _key
}
if (newMap.contains(_key)) {
remove = true
}
}
}
I'm completely new at Scala. I have taken this as my first Scala example, please any hints from Scala's Gurus is welcome.
稍微简单一点的版本
set.flatMap(_.find(map.contains).map(y => y -> map(y)))