这两种方法的优点/缺点是什么?
return items.Select(item => DoSomething(item));
Run Code Online (Sandbox Code Playgroud)
与
foreach(var item in items)
{
yield return DoSomething(item);
}
Run Code Online (Sandbox Code Playgroud)
编辑因为他们是MSIL大致相当,你发现哪一个更具可读性?
背景:我有一系列连续的,带时间戳的数据.数据序列中有孔,有些大,有些只有一个缺失值.
每当孔只是一个缺失值时,我想使用虚拟值修补孔(较大的孔将被忽略).
我想使用延迟生成修补序列,因此我使用Seq.unfold.
我已经制作了两个版本的方法来修补数据中的漏洞.
第一个消耗带有孔的数据序列并产生修补序列.这就是我想要的,但是当输入序列中的元素数量超过1000时,方法运行得非常慢,并且输入序列包含的元素越多,它就会越来越差.
第二种方法使用带有孔的数据列表并生成修补序列并且运行速度很快.然而,这不是我想要的,因为这会强制整个输入列表在内存中的实例化.
我想使用(sequence - > sequence)方法而不是(list - > sequence)方法,以避免在内存中同时存在整个输入列表.
问题:
1)为什么第一种方法如此缓慢(使用较大的输入列表逐渐变得更糟)(我怀疑它与使用Seq.skip 1重复创建新序列有关,但我不确定)
2)如何使用输入序列而不是输入列表快速修补数据中的空洞?
代码:
open System
// Method 1 (Slow)
let insertDummyValuesWhereASingleValueIsMissing1 (timeBetweenContiguousValues : TimeSpan) (values : seq<(DateTime * float)>) =
let sizeOfHolesToPatch = timeBetweenContiguousValues.Add timeBetweenContiguousValues // Only insert dummy-values when the gap is twice the normal
(None, values) |> Seq.unfold (fun (prevValue, restOfValues) ->
if restOfValues |> Seq.isEmpty then
None // Reached the …Run Code Online (Sandbox Code Playgroud) 我正在为博士研究编写代码并开始使用Scala.我经常要做文字处理.我已经习惯了Python,其'yield'语句对于在大型(通常是不规则结构化的)文本文件上实现复杂的迭代器非常有用.类似的结构存在于其他语言(例如C#)中,这是有充分理由的.
是的我知道之前有过这样的线索.但它们看起来像是黑客攻击(或至少解释得很糟糕)的解决方案,这些解决方案并不能很好地运作并且通常具有不明确的局限性.我想编写这样的代码:
import generator._
def yield_values(file:String) = {
generate {
for (x <- Source.fromFile(file).getLines()) {
# Scala is already using the 'yield' keyword.
give("something")
for (field <- ":".r.split(x)) {
if (field contains "/") {
for (subfield <- "/".r.split(field)) { give(subfield) }
} else {
// Scala has no 'continue'. IMO that should be considered
// a bug in Scala.
// Preferred: if (field.startsWith("#")) continue
// Actual: Need to indent all following code
if (!field.startsWith("#")) {
val some_calculation = { ... …Run Code Online (Sandbox Code Playgroud) 我很确定我对发电机的理解本质上已被打破.所有在线资源似乎都存在冲突,这会带来令人难以置信的困难和令人困惑的学习体验.
据我所知,该yield关键字使当前正在执行的代码块等待一个值,而不是抛出要在回调中执行的剩余代码.因此,正如大多数教程所指出的那样,您可以使用:
(function *() {
// Wait until users have be got and put into value of `results`
var results = yield db.get("users");
// And continue
view.display(results);
})();
Run Code Online (Sandbox Code Playgroud)
代替:
db.get("user", function(results) {
view.display(results);
});
Run Code Online (Sandbox Code Playgroud)
是的,在我尝试编写自己的发电机之前,这一切都很好.我遇到了几个问题:
.next某个地方,对吗?yield似乎代表值等待最常见的用例,而在实现部分(读取:返回值为/ inside db.get)yield似乎代表将此值发送回当前正在等待的块以恢复执行.举个例子:
function *fn() {
yield 1;
yield "a";
}
var gen = fn();
gen.next(); // 1
gen.next(); // "a";
Run Code Online (Sandbox Code Playgroud)
yield在该上下文中,将值返回而不是等待结果.在上面的第一个示例中,它等待来自db.get和恢复执行的结果,而不是"返回"或发回一个值.如果db.get情况属实,这本身并不是同步的吗?我的意思是,它不完全相同: …
我有两个发电机说A()和B().我想一起迭代两个生成器.就像是:
for a,b in A(),B(): # I know this is wrong
#do processing on a and b
Run Code Online (Sandbox Code Playgroud)
一种方法是将两个函数的结果存储在列表中,然后遍历合并列表.像这样的东西:
resA = [a for a in A()]
resB = [b for b in B()]
for a,b in zip(resA, resB):
#do stuff
Run Code Online (Sandbox Code Playgroud)
如果您想知道,那么两个函数都会产生相同数量的值.
但是我不能使用这种方法因为A()/B()返回了这么多的值.将它们存储在列表中会耗尽内存,这就是我使用生成器的原因.
有没有办法一次循环两个发电机?
我想知道使用yield return而不是返回列表是否存在任何并发(现在或将来)或性能优势.请参阅以下示例
处理方法
void Page_Load()
{
foreach(var item in GetPostedItems())
Process(item);
}
Run Code Online (Sandbox Code Playgroud)
使用收益率回报
IEnumerable<string> GetPostedItems()
{
yield return Item1.Text;
yield return Item2.Text;
yield return Item3.Text;
}
Run Code Online (Sandbox Code Playgroud)
返回一个清单
IEnumerable<string> GetPostedItems()
{
var list = new List<string>();
list.Add(Item1.Text);
list.Add(Item2.Text);
list.Add(Item3.Text);
return list;
}
Run Code Online (Sandbox Code Playgroud) public IEnumerable<ModuleData> ListModules()
{
foreach (XElement m in Source.Descendants("Module"))
{
yield return new ModuleData(m.Element("ModuleID").Value);
}
}
Run Code Online (Sandbox Code Playgroud)
最初上面的代码很棒,因为如果不需要,就不需要评估整个集合.
但是,一旦枚举了所有模块,在没有更改时重复查询XDocument会变得更加昂贵.
因此,作为绩效改进:
public IEnumerable<ModuleData> ListModules()
{
if (Modules == null)
{
Modules = new List<ModuleData>();
foreach (XElement m in Source.Descendants("Module"))
{
Modules.Add(new ModuleData(m.Element("ModuleID").Value, 1, 1));
}
}
return Modules;
}
Run Code Online (Sandbox Code Playgroud)
如果我反复使用整个列表,那就太好了,但不是那么好.
是否存在中间点,我可以在整个列表被迭代之前返回,然后缓存它并将缓存提供给后续请求?
yield用于调用块.这在Rails中如何yield用于布局?
-# application.html.haml
%body= yield
Run Code Online (Sandbox Code Playgroud)
它是在某处使用块还是简单地覆盖了方法?
我在python中有一个函数,其输出是一个生成器:
def main_function(x):
r = get_range()
for i in range(r):
yield x+i
Run Code Online (Sandbox Code Playgroud)
我想重构代码(我已经简化了用例,但实际的计算可能很复杂而且更长.请参阅下面的编辑).根据我的理解,这是我应该做的,以保持功能不变:
(a)与原始代码相同的界面
def sub_function(x,r):
for i in range(r):
yield x+i
def main_function(x):
r = get_range()
return sub_function(x,r)
Run Code Online (Sandbox Code Playgroud)
与其他方法相比:
(b)这将返回发电机的发电机(这种方法有什么优点吗?)
def sub_function(x,r):
for i in range(r):
yield x+i
def main_function(x):
r = get_range()
yield sub_function(x,r)
Run Code Online (Sandbox Code Playgroud)
(c)这会破坏发电机的目的(这是正确的吗?)
def sub_function(x,r):
return [x+i for i in range(r)]
def main_function(x):
r = get_range()
for i in sub_function(x,r):
yield(i)
Run Code Online (Sandbox Code Playgroud)
编辑:评论指出正确的答案是用例依赖.我想补充一点,我的用例是解析XML文件以提取字段并将其写入数据库.这部分委托给sub_function().我还问了这个问题,以便对重构代码的嵌套yield的使用有一个大致的了解.
yield ×10
c# ×4
generator ×4
python ×3
.net ×1
asp.net ×1
block ×1
enumerators ×1
f# ×1
for-loop ×1
ienumerable ×1
javascript ×1
linq ×1
loops ×1
methods ×1
nested ×1
node.js ×1
performance ×1
return ×1
ruby ×1
scala ×1
select ×1
seq.unfold ×1