我试图使用另一个(较短的)序列映射序列的子集,同时保留不在子集中的元素。下面的玩具示例试图仅向女性献花:
def giveFemalesFlowers(people: Seq[Person], flowers: Seq[Flower]): Seq[Person] = {
require(people.count(_.isFemale) == flowers.length)
magic(people, flowers)(_.isFemale)((p, f) => p.withFlower(f))
}
def magic(people: Seq[Person], flowers: Seq[Flower])(predicate: Person => Boolean)
(mapping: (Person, Flower) => Person): Seq[Person] = ???
有没有一种优雅的方式来实现魔法?
答案 0 :(得分:2)
每次flowers
成立时,使用predicate
上的迭代器,消耗一个;代码看起来像这样,
val it = flowers.iterator
people.map ( p => if (predicate(p)) p.withFlowers(it.next) else p )
答案 1 :(得分:0)
zip(又名zipWith)怎么样?
scala> val people = List("m","m","m","f","f","m","f")
people: List[String] = List(m, m, m, f, f, m, f)
scala> val flowers = List("f1","f2","f3")
flowers: List[String] = List(f1, f2, f3)
scala> def comb(xs:List[String],ys:List[String]):List[String] = (xs,ys) match {
| case (x :: xs, y :: ys) if x=="f" => (x+y) :: comb(xs,ys)
| case (x :: xs,ys) => x :: comb(xs,ys)
| case (Nil,Nil) => Nil
| }
scala> comb(people, flowers)
res1: List[String] = List(m, m, m, ff1, ff2, m, ff3)
如果订单不重要,您可以获得这个优雅的代码:
scala> val (men,women) = people.partition(_=="m")
men: List[String] = List(m, m, m, m)
women: List[String] = List(f, f, f)
scala> men ++ (women,flowers).zipped.map(_+_)
res2: List[String] = List(m, m, m, m, ff1, ff2, ff3)
答案 2 :(得分:0)
我打算假设你想要保留所有的起始人(不仅仅是过滤掉女性并失去男性),也按照原来的顺序。
嗯,有点难看,但我想出的是:def giveFemalesFlowers(people: Seq[Person], flowers: Seq[Flower]): Seq[Person] = {
require(people.count(_.isFemale) == flowers.length)
people.foldLeft((List[Person]() -> flowers)){ (acc, p) => p match {
case pp: Person if pp.isFemale => ( (pp.withFlower(acc._2.head) :: acc._1) -> acc._2.tail)
case pp: Person => ( (pp :: acc._1) -> acc._2)
} }._1.reverse
}
基本上,向左折叠,初始化累加器'一对由一个空的人名单和完整的鲜花列表组成,然后骑自行车穿过那些人。
如果当前人是女性,则将其传递给当前花卉列表的头部('累加器'的第2个字段),然后将更新后的累加器设置为更新后的人员(增长) )加工人员名单,以及(缩小)鲜花名单的尾部。
如果是男性,只需在处理过的人员名单前面,保持花朵不变。
在折叠结束时,'累加器的字段2' (花)应该是一个空列表,而第一个字段包含所有人(任何女性各自收到自己的花),按相反的顺序,所以以._1.reverse
编辑:尝试澄清代码(并替换类似于@ elm' s的测试以替换match
) - 希望更清楚地说明什么是继续,@ Felix! (不,没有冒犯):
def giveFemalesFlowers(people: Seq[Person], flowers: Seq[Flower]): Seq[Person] = {
require(people.count(_.isFemale) == flowers.length)
val start: (List[Person], Seq[Flower]) = (List[Person](), flowers)
val result: (List[Person], Seq[Flower]) = people.foldLeft(start){ (acc, p) =>
val (pList, fList) = acc
if (p.isFemale) {
(p.withFlower(fList.head) :: pList, fList.tail)
} else {
(p :: pList, fList)
}
}
result._1.reverse
}
答案 3 :(得分:-1)
我显然错过了一些东西,但不仅仅是
people map {
case p if p.isFemale => p.withFlower(f)
case p => p
}