问题描述
在Scala中,我有一个类似于以下内容的List [String]:
val xs = List("apple","orange",...,"pear","dragonfruit")
我想生成以下结果列表:
List(("apple",","),("orange",("pear",("dragonfruit",";"))
请注意,最后一对具有分号而不是逗号。 我可以不知道清单的长度吗?更一般而言,是否有适用于Iterable的功能版本?
def pairUp[A,B](xs: Iterable[A],nonlastB: B,lastB: B): Iterable[(A,B)]
xs中的每个x都应该与nonlastB
配对,最后一个与lastB
配对。
解决方法
为此使用foldRight
。
在您的示例中,您有
"apple" :: "orange" :: ... :: "pear" :: "dragonfruit" :: Nil
你想要
("apple",",") :: ("orange",") :: ... :: ("pear",") :: ("dragonfruit",";") :: Nil
foldRight的直觉是它可以进行构造函数替换。
l.foldRight
采用两个参数。第一个替换构造函数Nil
,第二个替换构造函数::
,所以您有了l.foldRight(nilReplacement)(consreplacement)
现在,让我们看一下您想要为Nil
和{ {1}}:
::
-
"apple" :: "orange" :: ... :: "pear" :: "dragonfruit" :: Nil ("apple",";") :: Nil
停留在Nil
-
Nil
成为x :: Nil
-
(x,";") :: Nil
成为x :: other
如此
(x,") :: other
不幸的是,您会发现val nilReplacement = Nil
val consReplacement = {
case x :: Nil => (x,";") :: Nil
case x :: other => (x,") :: other
}
xs.foldRight(nilReplacement)(consReplacement)
不能正确地进行类型检查,因为没有预期的类型,并且它会很快推断出val consreplacement
的错误类型。但是提供足够的类型提示可以解决该问题:
Nil
一种完全不同的方法可以通过迭代直接实现:
xs.foldRight[(String,String)](Nil) {
case x :: Nil => (x,") :: other
}
您可以使用stdlib中稍微复杂的import scala.collection.mutable.Builder
def pairUp[A,B](as: Iterable[A],nonlastB: B,lastB: B): Iterable[(A,B)] = {
val it = as.iterator
val builder = as.iterableFactory.newBuilder[(A,B)]
def loop(prev: A): Unit = {
if (it.hasNext) {
builder.addOne(prev -> nonlastB)
loop(it.next())
} else builder.addOne(prev -> lastB)
}
if(it.hasNext) loop(it.next())
builder.result()
}
基础结构来抽象输入类型:
Factory
,
我将建议2个选项,它可能比此处建议的其他答案效率低。但是它们很简单而且简短。
首先,删除最后一个元素,然后在以后添加它:
class Basis
{
public:
virtual int function(int i = 1) { return 2; }
};
class Sub : public Basis
{
public:
int function(int i = 5) override { return i; }
};
int main()
{
Basis* a[2];
a[0] = new Sub();
cout << a[0]->function(); //gives 1
}
我想到的第二个选择就是在xs.dropRight(1).map(l => (l,nonlastB)) ++ xs.lastOption.map(last => (last,lastB))
上滑动,并用分号显式添加最后一个项目:
iterable
代码运行可以在Scastie上找到。