提取集合

如何解决提取集合

| 最近,我为Anys的笛卡尔乘积编写了一个迭代器,并从List列表开始,但认识到我可以轻松切换到更抽象的特征Seq。 我知道,您喜欢看代码。 :)
class Cartesian (val ll: Seq[Seq[_]]) extends Iterator [Seq[_]] {

  def combicount: Int = (1 /: ll) (_ * _.length)

  val last = combicount
  var iter = 0

  override def hasNext (): Boolean = iter < last
  override def next (): Seq[_] = {
    val res = combination (ll,iter)
    iter += 1
    res
  }

  def combination (xx: Seq [Seq[_]],i: Int): List[_] = xx match {
      case Nil     => Nil
      case x :: xs => x (i % x.length) :: combination (xs,i / x.length) 
  }
}
和该类别的客户:
object Main extends Application {
  val illi = new Cartesian (List (\"abc\".toList,\"xy\".toList,\"AB\".toList))
  // val ivvi = new Cartesian (Vector (Vector (1,2,3),Vector (10,20)))
  val issi = new Cartesian (Seq (Seq (1,Seq (10,20)))
  // val iaai = new Cartesian (Array (Array (1,Array (10,20)))

  (0 to 5).foreach (dummy => println (illi.next ()))
  // (0 to 5).foreach (dummy => println (issi.next ()))
}
/*
List(a,x,A)
List(b,A)
List(c,A)
List(a,y,A)
*/
该代码适用于Seq和List(它们是Seqs),但是当然不适用于数组或Vector,它们不是Seq类型,并且没有约束方法\':: \'。 但是逻辑也可以用于此类集合。 我可以尝试为Vector,Array等编写与Seq之间的隐式转换,或者尝试编写自己的类似实现,或者编写Wrapper,将包装转换为Seq的Seq,然后调用\'hasNext内部集合的\'和\'next \',并将结果转换为Array,Vector或其他任何形式。 (我尝试实现这种解决方法,但我必须认识到:这并不容易。对于现实世界中的问题,我可能会独立地重写Iterator。) 但是,如果我必须处理列表数组或数组列表以及其他混合情况,那么整个事情就会失去控制。 用最广泛,可能的方式编写算法的最优雅方法是什么?     

解决方法

有两种解决方案。第一个是不要求容器是某个泛型超类的子类,而是可以转换为一个(通过使用隐式函数参数)。如果容器已经是所需类型的子类,则有一个预定义的标识转换,仅将其返回。
import collection.mutable.Builder
import collection.TraversableLike
import collection.generic.CanBuildFrom
import collection.mutable.SeqLike

class Cartesian[T,ST[T],TT[S]](val ll: TT[ST[T]])(implicit cbf: CanBuildFrom[Nothing,T,ST[T]],seqLike: ST[T] =>  SeqLike[T,traversableLike: TT[ST[T]] => TraversableLike[ST[T],TT[ST[T]]] ) extends Iterator[ST[T]] {

  def combicount (): Int = (1 /: ll) (_ * _.length)

  val last = combicount - 1 
  var iter = 0

  override def hasNext (): Boolean = iter < last
  override def next (): ST[T] = {
    val res = combination (ll,iter,cbf())
    iter += 1
    res
  }

  def combination (xx: TT[ST[T]],i: Int,builder: Builder[T,ST[T]]): ST[T] = 
    if (xx.isEmpty) builder.result
    else  combination (xx.tail,i / xx.head.length,builder += xx.head (i % xx.head.length) ) 
}
这类作品:
scala> new Cartesian[String,Vector,Vector](Vector(Vector(\"a\"),Vector(\"xy\"),Vector(\"AB\")))
res0: Cartesian[String,Vector] = empty iterator

scala> new Cartesian[String,Array,Array](Array(Array(\"a\"),Array(\"xy\"),Array(\"AB\")))
res1: Cartesian[String,Array] = empty iterator
由于错误https://issues.scala-lang.org/browse/SI-3343,我需要显式传递类型 需要注意的一件事是,这比使用存在类型更好,因为在迭代器上调用next返回正确的类型,而不是Seq [Any]。 这里有几个缺点: 如果容器不是所需类型的子类,则将其转换为一个,这会降低性能 该算法不是完全通用的。我们只需要使用这些类型提供的功能子集将类型转换为SeqLike或TraversableLike。因此,制作转换函数可能很棘手。 如果某些功能可以在不同的上下文中进行不同的解释怎么办?例如,一个矩形具有两个\'length \'属性(宽度和高度) 现在为替代解决方案。我们注意到,我们实际上并不关心集合的类型,而只是关心它们的功能: TT应该有
foldLeft
get(i: Int)
(头/尾) ST应该有
length
get(i: Int)
和一个Builder 所以我们可以对它们进行编码:
trait HasGet[T,CC[_]]  {
  def get(cc: CC[T],i: Int): T
}

object HasGet {
  implicit def seqLikeHasGet[T,CC[X] <: SeqLike[X,_]] = new HasGet[T,CC] {
    def get(cc: CC[T],i: Int): T = cc(i)
  }

  implicit def arrayHasGet[T] = new HasGet[T,Array] {
    def get(cc: Array[T],i: Int): T = cc(i)
  }
}

trait HasLength[CC] {
  def length(cc: CC): Int 
}

object HasLength {
  implicit def seqLikeHasLength[CC <: SeqLike[_,_]] = new HasLength[CC] {
    def length(cc: CC) = cc.length
  }

  implicit def arrayHasLength[T] = new HasLength[Array[T]] {
    def length(cc: Array[T]) = cc.length
  }

}   

trait HasFold[T,CC[_]] {
  def foldLeft[A](cc: CC[T],zero: A)(op: (A,T) => A): A
}

object HasFold {
  implicit def seqLikeHasFold[T,_]] = new HasFold[T,CC] {
    def foldLeft[A](cc: CC[T],T) => A): A = cc.foldLeft(zero)(op)
  }
  implicit def arrayHasFold[T] = new HasFold[T,Array] {
    def foldLeft[A](cc: Array[T],T) => A): A =  {
      var i = 0
      var result = zero
      while (i < cc.length) {
        result = op(result,cc(i))
        i += 1
      }
      result
    }
  }
}   
(严格来说,HasFold不是必需的,因为它的实现是基于长度和获取的,但是我在这里添加了它,以便算法可以更清晰地转换) 现在的算法是:
class Cartesian[T,ST[_],TT[Y]](val ll: TT[ST[T]])(implicit cbf: CanBuildFrom[Nothing,stHasLength: HasLength[ST[T]],stHasGet: HasGet[T,ST],ttHasFold: HasFold[ST[T],TT],ttHasGet: HasGet[ST[T],ttHasLength: HasLength[TT[ST[T]]]) extends Iterator[ST[T]] {

  def combicount (): Int = ttHasFold.foldLeft(ll,1)((a,l) => a * stHasLength.length(l))

  val last = combicount - 1 
  var iter = 0

  override def hasNext (): Boolean = iter < last
  override def next (): ST[T] = {
    val res = combination (ll,j: Int,ST[T]]): ST[T] = 
    if (ttHasLength.length(xx) == j) builder.result
    else  {
      val head = ttHasGet.get(xx,j)
      val headLength = stHasLength.length(head)
      combination (xx,j + 1,i / headLength,builder += stHasGet.get(head,(i % headLength) )) 
    }
}
并使用:
scala> new Cartesian[String,List](List(Vector(\"a\"),Vector(\"AB\")))
res6: Cartesian[String,List] = empty iterator

scala> new Cartesian[String,Array(\"AB\")))
res7: Cartesian[String,Array] = empty iterator
Scalaz可能已经为您提供了所有预定义的功能,但不幸的是,我不太了解。 (再次,我需要传递类型,因为推断不能推断正确的种类) 好处是该算法现在是完全通用的,并且不需要从Array到WrappedArray的隐式转换即可运行 锻炼:为元组定义;-)     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-