foldLeft,初始化第一个操作并先跳过

时间:2015-06-24 19:19:55

标签: scala functional-programming scala-collections

我有一个我foldLeft来收集另一个集合的集合。我使用所需类型的空集合初始化foldLeft

collection1.foldLeft(collection[T]())(op)

我的第一个测试测试fold操作中的集合是否为空,然后如果是,则从fold ed集合中创建一个集合。

collection1.foldLeft(collection[T]())({
  { case(t,otherstuff) =>
     if(t.isEmpty) new T(otherstuff) else ...}
})

看到我是如何初始化一个空集合并总是抛弃它,是否可以在初始化阶段创建初始集合(对空集合的响应)?

collection1.foldLeft(new T(collection1.first))({ // but SKIP first
  { case(t,otherstuff) =>
     ...}
})

2 个答案:

答案 0 :(得分:0)

这主要是让我觉得一个坏主意,你用一个空集合初始化累加器的原因是你可以统一操作,即通常你没有像if(t.isEmpty) ... else ...这样的特殊情况逻辑

我不知道你的应用程序,所以让我们假设你真的需要这样做,无论你在普通操作中做什么,都需要一个非空的Collection,它必须首先用一个包含第一次遇到元素,但之后必须以不同的方式运作。

首先要指出的是,您现有的方法可能并不可怕。您正在努力消除一个对象分配,这不太可能是性能瓶颈。 “过早的优化是所有邪恶的根源”,sez Donald Knuth。

要指出的第二点是,你通常不应该在scala中创建一个空集合collection[T]()。如果collection代表某个集合类或特征的名称,则可能有一个类似collection.empty[T]的方法,它每次都提供一个没有新分配的空实例。所以最简单的优化只是......

collection1.foldLeft(collection.empty[T])({
  { case(t,otherstuff) =>
     if(t.isEmpty) new T(otherstuff) else ...}
})

如果collection代表其伴侣不提供空方法的某个自定义不可变集合类,请在集合的伴随对象中定义一个(如果可以的话),如果不能,则在别处定义。

private val emptyCollection = collection[Nothing]() 
def empty[T] : collection = emptyCollection.asInstanceOf[T]

如果您确定折叠的集合将包含至少一个元素,则每次都可以避免空检查:

val pair = collection1.splitAt(1)
pair._2.foldLeft(pair._1){(col, next) =>
  ...
}

...是原始空检查的else个案例,不再需要if。为了做到这一点,将其包装在测试中

if ( !collection1.isEmpty ) {
  val pair = collection1.splitAt(1)
  pair._2.foldLeft(pair._1){(col, next) =>
    ...
  }
} else {
  appropriateDefaultResult
}

答案 1 :(得分:0)

您真的不想使用fold来产生另一个集合。折叠本质上是一种变异reducereduce使用some value in the collection as a starting point来累积值,并且为designed specifically for a commutative and associative operation on a collectionfold操作缺少这两个约束,但它们不能拆分为并发操作,因为每个累积必须按顺序发生。

是否有理由认为标准的循环列表推导不适合你?