检查Array [T]是否排序时没有局部tailrec?

时间:2018-09-21 08:47:47

标签: scala

Implement isSorted,它检查Array [A]是否根据给定的比较函数进行排序:

  

def isSorted [A](例如:Array [A],顺序:(A,A)=>布尔值):布尔值

这是我的实现方式

public void ConfigureServices(IServiceCollection services)
{
        services.AddAuthentication(options =>
                {
                    options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                })
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
                    {
                        options.LoginPath = "/auth";
                        //https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.cookiebuilder?view=aspnetcore-2.1
                        options.Cookie = new CookieBuilder
                        {
                            Name = "CustomCookie",
                            HttpOnly = false
                        };
                    });
}

public async void Configure(IApplicationBuilder app)
{
     app.UseAuthentication();
}

我遇到了这个异常:
 @tailrec def isSorted[A](as: Array[A], ordered: (A, A) => Boolean): Boolean = { if(as.length==0 || as.length == 1 || as.isEmpty) true else if(!ordered(as(0),as(1))) false isSorted(as.tail,ordered) }

我不太了解,当java.lang.UnsupportedOperationException: empty.tail为空时,它应该返回true。

2 个答案:

答案 0 :(得分:4)

在Scala中,在方法或块内求值的最后一个表达式成为该方法或块的值。

在您的情况下,在方法内部求值的最后一个表达式是:

isSorted(as.tail,ordered)

因此,这是返回值。 总是

在该表达式之前,您的方法中还有另一个表达式:

if(as.length==0 || as.length == 1 || as.isEmpty) true
else if(!ordered(as(0),as(1))) false

但是:

  • 此表达没有副作用
  • 该表达式的值不会存储在任何地方
  • 不返回该表达式的值

因此,此表达式本质上是无操作的,而您的方法实际上就是这样:

@tailrec
def isSorted[A](as: Array[A], ordered: (A, A) => Boolean): Boolean = 
  isSorted(as.tail,ordered)

您的方法将简单地递归直到数组为空,然后抛出异常,因为您尝试使用空数组的尾部再次递归。

最简单的解决方法是使最后一个表达式成为较大表达式的一部分,以便您的方法仅包含一个表达式:

@tailrec
def isSorted[A](as: Array[A], ordered: (A, A) => Boolean): Boolean = {
  if(as.length==0 || as.length == 1 || as.isEmpty) true
  else if(!ordered(as(0),as(1))) false
  else isSorted(as.tail,ordered)
//↑↑↑↑ This is the only change needed.
}

现在,让我们进行一次小型游览:Scala风格!

您的空白样式不一致。有时,运算符周围会有空格,有时却没有,并且不清楚何时选择一个或另一个,其含义是什么。例如,在这里:

if(as.length==0 || as.length == 1 || as.isEmpty) true
//          ↑↑ ↑↑↑↑         ↑↑↑↑ ↑↑↑↑

您使用什么标准来决定何时使用空白?您在||和第二个==而不是第一个if(as.length == 0 || as.length == 1 || as.isEmpty) true // ↑↑↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑↑ 周围使用空格是什么意思?您希望通过该决定告诉我什么,代码的读者吗?

我个人会这样写:

else if(!ordered(as(0), as(1))) false
//                     ↑
else isSorted(as.tail, ordered)
//                    ↑

这也与标准《 Scala社区风格指南》保持一致。

同样,您在参数列表中的逗号后使用空格,而在参数列表中不使用空格。标准的《 Scala社区样式指南》建议在逗号后使用空格以提高可读性:

if

标准的《 Scala社区风格指南》还建议在控制流关键字(例如whileif (as.length == 0 || as.length == 1 || as.isEmpty) true //↑ else if (!ordered(as(0), as(1))) false // ↑ 之后使用空格,以将它们与方法调用区分开来:

if (as.length == 1 || as.isEmpty) true

此外,请注意,检查零长度和空度是多余的,它们是同一回事:

@tailrec
def isSorted[A](as: Array[A], ordered: (A, A) => Boolean): Boolean = 
  if (as.length == 1 || as.isEmpty) true
  else if (!ordered(as(0), as(1))) false
  else isSorted(as.tail, ordered)

最后,既然我们的方法只包含一个表达式,我们就不再需要花括号了。

def isSorted[A](as: Array[A], ordered: (A, A) => Boolean) = 
  as.sliding(2).forall { case Array(a, b) => ordered(a, b) }

但是,实际上有一种更好的方法可以解决此问题:如果对每个连续的元素对都进行排序,则对数组进行排序:

A

您的方法签名不方便。类型推断只会从一个参数列表流到下一个参数列表,而不会在一个参数列表内,因此在您的情况下,编译器将不知道ordered中的A是什么,即使它已经知道了什么。 asisSorted(Array(1, 5, 3, 4), (a, b) => a < b) // error: missing parameter type // isSorted(Array(1, 5, 3, 4), (a, b) => a < b) // ^ // error: missing parameter type // isSorted(Array(1, 5, 3, 4), (a, b) => a < b) // ^ 中:

isSorted(Array(1, 5, 3, 4), (a: Int, b: Int) => a < b)
//=> res: Boolean = false

您必须明确告诉编译器类型:

def isSorted[A](as: Array[A])(ordered: (A, A) => Boolean) = 
  as.sliding(2).forall { case Array(a, b) => ordered(a, b) }

因此,最好将功能参数放在单独的参数列表中:

isSorted(Array(1, 5, 3, 4))((a, b) => a < b)
//=> res: Boolean = false

现在,类型推断可以按预期工作:

isSorted(Array(1, 5, 3, 4)) { _ < _ }
//=> res: Boolean = false

您还可以使用占位符阻止函数的语法:

as

最后,签名实际上受到了不必要的限制:实际上并没有要求Array成为Seq,它对于更通用的类型(例如{{1})也同样适用}:

def isSorted[A](as: Seq[A])(ordered: (A, A) => Boolean) = 
  as.sliding(2).forall { case Seq(a, b) => ordered(a, b) }

现在,例如,我们也可以传递List而不是仅传递Array。实际上,只需重写一下该方法,就应该有可能使它适用于 all Iterable s。

答案 1 :(得分:0)

使用返回关键字:

@tailrec
  def isSorted[A](as: Array[A], ordered: (A, A) => Boolean): Boolean = {
    if (as.length == 0 || as.length == 1 || as.isEmpty) return true
    else if (!ordered(as(0), as(1))) return false
    isSorted(as.tail, ordered)
  }

或者您可以执行此操作(建议):

@tailrec
      def isSorted[A](as: Array[A], ordered: (A, A) => Boolean): Boolean = {
        if (as.length == 0 || as.length == 1 || as.isEmpty) return true
        else if (!ordered(as(0), as(1))) return false
        else isSorted(as.tail, ordered)
      }