我是Scala的新手,并且尝试在下面了解此程序。特别是我听不懂这行
case _ :: tail =>
lastNthR(count - 1,
if (count > 0) resultList else resultList.tail,
tail)
让我们说我必须找到最后一个第二个元素6,代码变成lastNthR(2-1=1
?,因为1> 0应该得到resultList
我在这里吗?其他resultlist.tail, tail
?
我不明白。有人可以向我解释一下。我挠了很久。这是完整的代码:
def lastNthRecursive[A](n: Int, ls: List[A]): A = {
def lastNthR(count: Int, resultList: List[A], curList: List[A]): A =
curList match {
case Nil if count > 0 => throw new NoSuchElementException
case Nil => resultList.head
case _ :: tail =>
lastNthR(count - 1,
if (count > 0) resultList else resultList.tail,
tail)
}
if (n <= 0) throw new IllegalArgumentException
else lastNthR(n, ls, ls)
}
println(lastNthRecursive(2,List(4,5,6,7)))
答案 0 :(得分:1)
我不确定这是标题中的错字还是您错过了,但是此方法(顾名思义)从末尾找到第N
个元素 < / em> (或以相反的顺序)以1
作为最后一个元素(这在编程中是不常见的表示法,通常索引以0
开头)。
我认为您搞砸了格式。让我们将此代码重写为等效形式:
if(count > 0) {
lastNthR(count - 1,
resultList,
tail)
}
else {
lastNthR(count - 1,
resultList.tail,
tail)
}
换句话说,在您的代码中,if(count > 0)
语句会影响lastNthR
调用中第二个参数的计算,而第一个参数(count - 1
)和第三个参数({{1} })是“固定的”,这就是在行尾用tail
表示的逗号(,
)。
从逻辑上讲,此代码分为两个阶段:
if
成立的第一阶段,我们将if(count > 0)
和curList
分别减小1,直到count
变为0。count
为假时,我们将if(count > 0)
和curList
分别减少1,直到resultList
为空。换句话说,算法说从末尾找到第curList
个元素与从头开始找到第n
个元素相同。第一阶段找到此length(list) - n
值(以该长度的列表表示),然后第二阶段从头开始进行搜索。
您可以重新编写该代码,用两种不同的方法将阶段明确地分开:
length(list) - n
P.S。我不喜欢这样的事实,即例外情况def lastNthRecursive[A](n: Int, ls: List[A]): A = {
// stage 1
// note, there is actually a very similar a standard method on a List
// but it doesn't fail in case of an overshot (n > length(list))
def dropN(count: Int, curList: List[A]): List[A] = curList match {
case _ if (count == 0) => curList // important to be above the Nil case
case Nil => throw new IndexOutOfBoundsException(s"$n is more than the list length")
case _ :: tail => dropN(count - 1, tail)
}
// stage 2
def dropAll(longList:List[A], shortList:List[A]):List[A] = shortList match {
case Nil => longList
case _ => dropAll(longList.tail, shortList.tail)
}
if (n < 0) throw new IndexOutOfBoundsException(s"$n is less than 0")
else {
val shortenedList = dropN(n, ls)
val resultList = dropAll(ls, shortenedList)
resultList.head
}
}
与IllegalArgumentException
不一致,并且根本没有提供文字描述。在这种情况下,恕我直言还有一个更好的例外-NoSuchElementException
答案 1 :(得分:1)
非常有趣的例子!
它使用列表和自身的副本来知道何时停止通过列表的元素。这是在每次调用lastNthR
时运行示例时发生的情况:
count = 2
resultList = List(4, 5, 6, 7)
curList = List(4, 5, 6, 7)
count = 1
resultList = List(4, 5, 6, 7)
curList = List(5, 6, 7)
count = 0
resultList = List(4, 5, 6, 7)
curList = List(6, 7)
count = -1
resultList = List(5, 6, 7)
curList = List(7)
count = -2
resultList = List(6, 7)
curList = List()
如您所见,在每一步中,它会将count
减1。尽管count
大于零,但它不会影响resultList
,顾名思义,curList
是我们用来获取最终结果的列表。但是,在每个步骤中,都会删除curList
中的第一个元素。该函数执行直到resultList
的元素用完为止。但是,从curList
中删除了前N个元素(在本例中为2个)之后,我们就开始从curList
中删除元素。这样,我们将用尽resultList
中的元素,而我们仍然拥有resultList
中的最后2个元素。
以一种更加图形化的方式,预期的效果就像我们将count: 2
resultList = 4, 5, 6, 7
curList = 4, 5, 6, 7
的两个位置向右移动一样:
curList
然后,我们开始一个接一个地删除元素,直到用尽count: 1
resultList = 4, 5, 6, 7
curList = 5, 6, 7
count: 0
resultList = 4, 5, 6, 7
curList = 6, 7
中的元素,这就是您指出的块所做的:
count
当resultList
为零或更低时,我们也开始从count: -1
resultList = 5, 6, 7
curList = 7
count: -2
resultList = 6, 7
curList =
中删除项目:
curList
这样,当我们用完resultList
中的项目时,我们仍然还有curList match {
// ...
case Nil => resultList.head
// ...
}
中剩下的2个元素,因此我们只需要获取第一个即可。这是通过代码完成的:
DirectoryIndex index.php
RewriteEngine On
RewriteRule ^$ public/index.php [L]
RewriteRule ^((?!public/).*)$ public/$1 [L,NC]
答案 2 :(得分:1)
从列表中获取第n个元素(已建立索引)的方法:
def get[A] (n: Int, list: List[A]): A = {
@scala.annotation.tailrec
def go(acc: Int, li: List[A]): A = {
if(acc == n) List.head(li)
else go(acc+1, tail(li))
}
if(n > List.length(list) - 1) throw new IllegalArgumentException("indexincompatible with List length");
go(0, list)
}
要从最后获取第n个元素,请使用从开始算起的索引进行调用。