概括“下一个排列”功能
下面是返回按字典顺序排列的下一个排列的函数的实现。这对于欧拉问题之一很有用。
它是为在字符串上工作而编写的(我需要它)。但是,它应该适用于可比较值的任何索引序列。我尝试通过将两次出现的 String 更改为 IndexedSeq[Char] 来概括它,但这会出现错误:
euler-lib.scala:26: error: type mismatch;
found : IndexedSeq[Char]
required: String
((n.slice(pivot+1, successor):+ n(pivot)) + n.drop(successor+1)).reverse
^
为什么类型推断器在那里推断出 String ?我好像没有做过任何需要String的操作?
我可以通过使用 IndexedSeq["something-comparable"] 使其更加通用吗?我没能完成这项工作。
// return the lexographically next permutation to the one passed as a parameter
// pseudo-code from an article on StackOverflow
def nextPermutation(n:String):String = {
// 1. scan the array from right-to-left
//1.1. if the current element is less than its right-hand neighbor,
// call the current element the pivot,
// and stop scanning
// (We scan left-to-right and return the last such).
val pivot = n.zip(n.tail).lastIndexWhere{ case (first, second) => first < second }
//1.2. if the left end is reached without finding a pivot,
// reverse the array and return
// (the permutation was the lexicographically last, so its time to start over)
if (pivot < 0) return n.reverse
//2. scan the array from right-to-left again,
// to find the rightmost element larger than the pivot
// (call that one the successor)
val successor = n.lastIndexWhere{_ > n(pivot)}
//3. swap the pivot and the successor, and
//4. reverse the portion of the array to the right of where the pivot was found
return (n.take(pivot) :+ n(successor)) +
((n.slice(pivot+1, successor):+ n(pivot)) + n.drop(successor+1)).reverse
}
Below is an implementation of a function that returns the lexographically next permutation. This is useful in one of the Euler problems.
It's written to work on Strings (which I needed for that). However, it should work on any indexed sequence of comparable values. I've tried generalising it by changing the two occurrences of String to IndexedSeq[Char], but this gets an error:
euler-lib.scala:26: error: type mismatch;
found : IndexedSeq[Char]
required: String
((n.slice(pivot+1, successor):+ n(pivot)) + n.drop(successor+1)).reverse
^
Why has the type inferencer inferred String there? I don't seem to have done any operation that requires a String?
And can I make it more general still by having IndexedSeq["something-comparable"]? I've not been able to make this work.
// return the lexographically next permutation to the one passed as a parameter
// pseudo-code from an article on StackOverflow
def nextPermutation(n:String):String = {
// 1. scan the array from right-to-left
//1.1. if the current element is less than its right-hand neighbor,
// call the current element the pivot,
// and stop scanning
// (We scan left-to-right and return the last such).
val pivot = n.zip(n.tail).lastIndexWhere{ case (first, second) => first < second }
//1.2. if the left end is reached without finding a pivot,
// reverse the array and return
// (the permutation was the lexicographically last, so its time to start over)
if (pivot < 0) return n.reverse
//2. scan the array from right-to-left again,
// to find the rightmost element larger than the pivot
// (call that one the successor)
val successor = n.lastIndexWhere{_ > n(pivot)}
//3. swap the pivot and the successor, and
//4. reverse the portion of the array to the right of where the pivot was found
return (n.take(pivot) :+ n(successor)) +
((n.slice(pivot+1, successor):+ n(pivot)) + n.drop(successor+1)).reverse
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
IndexedSeq
中的方法+
用于生成一个包含一个附加给定元素的新序列,但您希望生成一个包含附加序列的序列。其方法是++
因此你的最后一行必须如下所示:你看到这个奇怪的编译器消息,关于需要
String
因为+
的签名不匹配,因此用于字符串连接的显式转换启动(此转换之所以存在,是因为它允许您编写类似List(8) + " Test"
的内容)。编辑:有序元素的序列类型的泛化:
正如我在评论中所说,序列的泛化有点复杂。除了元素类型
A
之外,您还需要另一种类型CC[X] <: SeqLike[X,CC[X]]
来表示序列。通常C <: SeqLike[A,C]
就足够了,但类型推断器不喜欢那个(您总是需要传递A
和 < code>C 调用该方法时)。如果您只是以这种方式更改签名,编译器会抱怨它需要隐式
CanBuildFrom[CC[A],A,CC[A]]
参数,因为需要该参数反向方法。该参数用于从另一种序列类型构建一种序列类型 - 只需搜索站点即可查看集合 API 如何使用它的一些示例。
最终结果如下所示:
这样,如果您将一个传递给该方法,您将获得一个
Vector[Int]
;如果您将其传递给该方法,您将获得一个List[Double]
方法。那么String
又如何呢?这些不是实际的序列,但可以隐式转换为Seq[Char]
。可以改变该方法的定义,期望某种可以隐式转换为 Seq[A] 的类型,但类型推断将无法可靠地工作 - 或者至少我无法使其可靠地工作。作为一个简单的解决方法,您可以为String
定义一个附加方法:The method
+
inIndexedSeq
is used to produce a new sequence containing one additional given element but you want to produce one containing an additional sequence. The method for this is++
thus your last line must look like this:You are seeing this strange compiler message about a
String
being expected because+
's signature does not match and thus an explicit conversion used for String concatenation kicks in (this conversion is there because it lets you write something likeList(8) + " Test"
).EDIT: Generalization over sequence types of ordered elements:
As I said in the comments, generalization over sequences is a bit more complicated. In addition to your element type
A
you will need another typeCC[X] <: SeqLike[X,CC[X]]
that represents the sequence. NormallyC <: SeqLike[A,C]
would be sufficient but the type inferencer does not like that one (you would always need to pass the types ofA
andC
when calling that method).If you just change your signature that way the compiler will complain that it requires an implicit
CanBuildFrom[CC[A],A,CC[A]]
parameter as that one is needed e.g. by thereverse
method. That parameter is used to build one sequence type from another one - just search the site to see some examples of how it is used by the collections API.The final result would look like this:
This way you get a
Vector[Int]
if you passed one to the method and aList[Double]
if you passed that to the method. So what aboutString
s? Those are not actual sequences but they can be implicitly converted into aSeq[Char]
. It is possible alter the definition of that method expect some type that can be implicitly converted into aSeq[A]
but then again type inference would not work reliably - or at least I could not make it work reliably. As a simple workaround you could define an additional method forString
s:这里的小提示:
当您收到类型不匹配错误时,
^
指向最后一个参数列表的第一个括号(即,它将指向第二个(
x.foldLeft(y)(z)),这意味着该方法返回的值的类型错误,或者在本例中为 n.drop。 (sucessor+1) 的类型为
IndexedSeq[Char]
,但+
方法需要一个String
另一个小提示:唯一接受
+
的是数字类和String
如果您尝试添加内容并收到错误,很可能是 Scala 认为您正在使用+。
添加字符串
例如:因此,除非您使用数字或字符串,否则请避免使用
+
因此,关于使其通用...
简单的部分。只是声明
IndexedSeq
,但是您必须对A
进行参数化,并且必须有一种方法对A
进行排序,以便您可以比较元素。 (<%
表示存在从A
到Ordered[A]
的隐式转换)。另一种声明方式是这样的:这里,
A : Ordering
意味着有一个隐式的Ordering[A]
可用,然后获取该值并将其导入到作用域中,因此它可以提供隐式转换以使<
工作。Ordered[A]
和Ordering[A]
之间的区别可以在其他问题中找到。Little tip here:
When you get a type mismatch error, and the
^
points to the first parenthesis of the last argument list (ie, it would point to the second(
inx.foldLeft(y)(z)
), that means the value returned by that method has the wrong type.Or, in this case,
n.drop(sucessor+1)
has typeIndexedSeq[Char]
, but the+
method expects aString
.Another little tip: the only things that accept
+
are the numeric classes andString
. If you try to add things and get an error, most likely it is Scala thinking you are using+
to addStrings
. For example:So, avoid
+
unless you are working with numbers or strings.So, about making that general...
The easy part is just declaring
IndexedSeq
. But you have to parameterize onA
, and there must be a way to orderA
so that you can compare the elements (<%
means there's an implicit conversion fromA
to anOrdered[A]
available). Another way to declare it would be like this:Here,
A : Ordering
means there is an implicitOrdering[A]
available, which is then obtained and imported into scope, so that it can offer implicit conversions to make<
work. The difference between anOrdered[A]
and anOrdering[A]
can be found on other questions.第24题让我难住了一段时间:
Problem 24 had me stumped for a while:
该代码在 Scala 2.8.0 中为我编译正确。您使用的是哪个版本的 Scala?
The code compiles correclty for me in Scala 2.8.0. Which version of Scala are you using ?