gpt4 book ai didi

Scala方法对 map 产生副作用并返回它

转载 作者:行者123 更新时间:2023-12-05 00:52:32 24 4
gpt4 key购买 nike

将函数应用于 Map 的每个元素的最佳方法是什么?最后返回相同的 Map ,不变,以便可以在进一步的操作中使用?

我想避免:

myMap.map(el => {
effectfullFn(el)
el
})

实现这样的语法:
myMap
.mapEffectOnKV(effectfullFn)
.foreach(println)
map不是我要找的,因为我必须指定 map 中出现的内容(如第一个代码片段中所示),而我不想这样做。

我想要一个特殊的操作,它知道/假设在执行副作用函数后应该不加更改地返回 map 元素。

事实上,这对我来说非常有用,我想把它用于 Map , Array , List , Seq , Iterable ... 大体思路是偷看元素做某事,然后自动返回这些元素。

我正在处理的真实案例如下所示:
 calculateStatistics(trainingData, indexMapLoaders)
.superMap { (featureShardId, shardStats) =>
val outputDir = summarizationOutputDir + "/" + featureShardId
val indexMap = indexMapLoaders(featureShardId).indexMapForDriver()
IOUtils.writeBasicStatistics(sc, shardStats, outputDir, indexMap)
}

一旦我计算了每个分片的统计信息,我想附加将它们保存到磁盘的副作用,然后只需返回这些统计信息,而不必创建 val并拥有 val的名称是函数中的最后一条语句,例如:
val stats = calculateStatistics(trainingData, indexMapLoaders)
stats.foreach { (featureShardId, shardStats) =>
val outputDir = summarizationOutputDir + "/" + featureShardId
val indexMap = indexMapLoaders(featureShardId).indexMapForDriver()
IOUtils.writeBasicStatistics(sc, shardStats, outputDir, indexMap)
}
stats

这可能不是很难实现,但我想知道 Scala 中是否已经有一些东西可以实现。

最佳答案

函数根据定义是无效的,所以我不希望在 Scala-lib 中有任何方便的东西。但是,您可以编写一个包装器:

def tap[T](effect: T => Unit)(x: T) = {
effect(x)
x
}

例子:
scala> Map(1 -> 1, 2 -> 2)
.map(tap(el => el._1 + 5 -> el._2))
.foreach(println)
(1,1)
(2,2)

您还可以定义一个隐式:
implicit class TapMap[K,V](m: Map[K,V]){
def tap(effect: ((K,V)) => Unit): Map[K,V] = m.map{x =>
effect(x)
x
}
}

例子:
scala> Map(1 -> 1, 2 -> 2).tap(el => el._1 + 5 -> el._2).foreach(println)
(1,1)
(2,2)

要抽象更多,您可以在 TraversableOnce 上定义这个隐式,所以它适用于 List , Set等等,如果你需要它:
implicit class TapTraversable[Coll[_], T](m: Coll[T])(implicit ev: Coll[T] <:< TraversableOnce[T]){
def tap(effect: T => Unit): Coll[T] = {
ev(m).foreach(effect)
m
}
}

scala> List(1,2,3).tap(println).map(_ + 1)
1
2
3
res24: List[Int] = List(2, 3, 4)

scala> Map(1 -> 1).tap(println).toMap //`toMap` is needed here for same reasons as it needed when you do `.map(f).toMap`
(1,1)
res5: scala.collection.immutable.Map[Int,Int] = Map(1 -> 1)

scala> Set(1).tap(println)
1
res6: scala.collection.immutable.Set[Int] = Set(1)

它更有用,但需要一些带有类型的“mamba-jumbo”,如 Coll[_] <: TraversableOnce[_]不起作用(Scala 2.12.1),所以我不得不为此使用证据。

你也可以试试 CanBuildFrom方法: How to enrich a TraversableOnce with my own generic map?

关于处理迭代器传递副作用的总体建议是使用 Stream s (scalaz/fs2/monix) 和 Task ,所以他们有一个 observe (或它的某种模拟)函数以异步(如果需要)方式执行您想要的操作。

在你提供你想要的例子之前我的回答

您可以表示没有副作用的有效计算,并具有表示前后状态的不同值:
scala> val withoutSideEffect = Map(1 -> 1, 2 -> 2)
withoutSideEffect: scala.collection.immutable.Map[Int,Int] = Map(1 -> 1, 2 -> 2)

scala> val withSideEffect = withoutSideEffect.map(el => el._1 + 5 -> (el._2 + 5))
withSideEffect: scala.collection.immutable.Map[Int,Int] = Map(6 -> 6, 7 -> 7)

scala> withoutSideEffect //unchanged
res0: scala.collection.immutable.Map[Int,Int] = Map(1 -> 1, 2 -> 2)

scala> withSideEffect //changed
res1: scala.collection.immutable.Map[Int,Int] = Map(6 -> 6, 7 -> 7)

关于Scala方法对 map 产生副作用并返回它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42522661/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com