当前位置: 首页 > 面试题库 >

Scala等同于Python生成器?

束俊材
2023-03-14
问题内容

是否可以在Scala中实现与Pythonyield语句等效的功能,在该语句中它记住使用该函数的局部状态,并在每次调用该函数时“产生”下一个值?

我希望有类似这样的东西可以将递归函数转换为迭代器。有点像这样:

# this is python
def foo(i):
  yield i
  if i > 0:
    for j in foo(i - 1):
      yield j

for i in foo(5):
  print i

除此以外,foo可能会更复杂并通过一些非循环对象图重复出现。

附加编辑: 让我添加一个更复杂的示例(但仍然很简单):我可以编写一个简单的递归函数,以进行打印:

// this is Scala
def printClass(clazz:Class[_], indent:String=""): Unit = {
  clazz match {
    case null =>
    case _ =>
      println(indent + clazz)
      printClass(clazz.getSuperclass, indent + "  ")
      for (c <- clazz.getInterfaces) {
        printClass(c, indent + "  ")
      }
  }
}

理想情况下,我希望拥有一个可以轻松更改一些语句并将其用作迭代器的库:

// this is not Scala
def yieldClass(clazz:Class[_]): Iterator[Class[_]] = {
  clazz match {
    case null =>
    case _ =>
      sudoYield clazz
      for (c <- yieldClass(clazz.getSuperclass)) sudoYield c
      for (c <- clazz.getInterfaces; d <- yieldClasss(c)) sudoYield d
  }
}

似乎延续允许这样做,但我只是不理解这个shift/reset概念。延续将最终使其进入主编译器,并且有可能提取出库中的复杂性吗?


问题答案:

尽管Python生成器很酷,但尝试复制它们确实不是Scala中最好的方法。例如,以下代码可以完成所需的工作:

def classStream(clazz: Class[_]): Stream[Class[_]] = clazz match {
  case null => Stream.empty
  case _ => (
    clazz 
    #:: classStream(clazz.getSuperclass) 
    #::: clazz.getInterfaces.toStream.flatMap(classStream) 
    #::: Stream.empty
  )
}

在其中,流是延迟生成的,因此它不会处理任何元素,直到被询问为止,您可以通过运行以下命令进行验证:

def classStream(clazz: Class[_]): Stream[Class[_]] = clazz match {
  case null => Stream.empty
  case _ => (
    clazz 
    #:: { println(clazz.toString+": super"); classStream(clazz.getSuperclass) } 
    #::: { println(clazz.toString+": interfaces"); clazz.getInterfaces.toStream.flatMap(classStream) } 
    #::: Stream.empty
  )
}

结果可以被转换成Iterator简单地通过调用.iterator对所得Stream

def classIterator(clazz: Class[_]): Iterator[Class[_]] = classStream(clazz).iterator

使用的foo定义Stream将这样呈现:

scala> def foo(i: Int): Stream[Int] = i #:: (if (i > 0) foo(i - 1) else Stream.empty)
foo: (i: Int)Stream[Int]

scala> foo(5) foreach println
5
4
3
2
1
0

另一种选择是将各种迭代器串联起来,注意不要预先计算它们。这是一个示例,其中还包含调试消息以帮助跟踪执行:

def yieldClass(clazz: Class[_]): Iterator[Class[_]] = clazz match {
  case null => println("empty"); Iterator.empty
  case _ =>
    def thisIterator = { println("self of "+clazz); Iterator(clazz) }
    def superIterator = { println("super of "+clazz); yieldClass(clazz.getSuperclass) }
    def interfacesIterator = { println("interfaces of "+clazz); clazz.getInterfaces.iterator flatMap yieldClass }
    thisIterator ++ superIterator ++ interfacesIterator
}

这非常接近您的代码。取而代之的是sudoYield,我有了定义,然后按需要将它们串联起来。

因此,尽管这是一个无法解决的问题,但我只是认为您在这里树错了树。尝试在Scala中编写Python肯定是徒劳的。在实现相同目标的Scala习惯用法上加倍努力。



 类似资料:
  • 问题内容: 我正在努力寻找一种方法,以根据谓词在流的开头跳过某些元素。 像这样: 那相当于Scala 。 问题答案: 这种操作不是s 的预期用例,因为它并入了元素之间的依赖关系。因此,该解决方案可能看起来不太好,因为您必须为谓词引入一个全状态变量: 请注意,与您的示例相比,该条件必须颠倒。 当然,您可以在方法中隐藏令人讨厌的细节: 一个更复杂,但更清洁,可能更有效的方法是深入研究金属,即界面: 可

  • 问题内容: 这是执行字符串替换的两种方法: 如何使用Java做与第一种方法类似的操作? 问题答案: 或更短:

  • 问题内容: 我目前正在玩《暴力Python》一书中的示例。你可以在这里看到我的实现 我现在正在尝试在Go中实现相同的脚本以比较性能,请注意我对Go来说是全新的。打开文件并遍历各行很好,但是我无法弄清楚如何使用“ crypto”库以与Python的crypt.crypt(str_to_hash,salt)相同的方式对字符串进行哈希处理。我想可能是这样的 但是,没有雪茄。任何帮助将不胜感激,因为将Go

  • 问题内容: 我已经找到了以下问题,但我想知道是否有一种更快,更脏的方法来估算不依赖外部库的python解释器当前正在使用多少内存。 我来自PHP,过去经常为此目的使用memory_get_usage()和memory_get_peak_usage(),我希望能找到一个等效的对象。 问题答案: 以下代码为Linux和其他系统提供了一个简单的解决方案,我在我的项目中使用了以下代码: 它返回当前和峰值驻

  • 问题内容: 经过多次尝试优化代码之后,似乎最后的资源就是尝试使用多个内核来运行以下代码。我不确切地知道如何转换/重组我的代码,以便它可以使用多个内核更快地运行。如果能得到指导以实现最终目标,我将不胜感激。最终目标是能够对数组A和B尽可能快地运行此代码,其中每个数组包含大约700,000个元素。这是使用小数组的代码。700k元素数组已被注释掉。 我想做的是模仿一个称为ismember [2]的MAT

  • 问题内容: 我发现compact()和extract()是PHP中的函数,非常方便。compact()在符号表中获取名称列表,并仅使用其值创建哈希表。提取相反。例如, 有没有办法在Python中做同样的事情?我环顾四周,最接近的就是这个线程,似乎对此不满意。 我知道locals(),globals()和vars(),但是如何方便地选择它们的一部分值呢? Python是否有更好的东西可以消除对此的需