嵌套循环的惯用Scala

时间:2016-12-13 12:44:04

标签: scala functional-programming

我正在尝试编写惯用的scala代码来遍历两个列表列表,并生成一个仅包含两个列表差异的新列表。

在程序Scala中我会做这样的事情:

val first: List[List[Int]]  = List(List(1,2,3,4,5),List(1,2,3,4,5),  List(1,2,3,4,5))
val second: List[List[Int]] = List(List(1,2,3,4,5),List(1,23,3,45,5),List(1,2,3,4,5))

var diff: List[String] = List[String]()
for (i <- List.range(0, first.size)){
  for (j <- List.range(0, first(0).size)){
    println(first(i)(j) + " " + second(i)(j))
    if (first(i)(j) != second(i)(j)) diff = diff ::: (s"${second(i)(j)}" :: Nil)
  }
}

当然我不喜欢这个,我试图用理解来写一个解决方案,但没有成功。

我能得到的最接近的是:

for {(lf,ls) <- (first zip second) } yield if (lf == ls) lf else ls

但是从理解中我无法生成与输入类型不同的String列表。

有什么建议吗?

2 个答案:

答案 0 :(得分:3)

惯用的Scala会是这样的:

(
  for {
    (row1, row2) <- (first, second).zipped   // go through rows with the same index
    (value1, value2) <- (row1, row2).zipped  // go through values with the same indexes
    if value1 != value2                      // leave only different values in the list
  } yield value2.toString
).toList

最好在zipped使用zip,而不是zipped,因为List不会在内存中生成整个压缩toList

此外,由于类型推断的怪癖,最后你必须using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Caching.Memory; using System; using Microsoft.Extensions.FileProviders; namespace CachingQuestion { public class Startup { static string CACHE_KEY = "CacheKey"; public void ConfigureServices(IServiceCollection services) { //enabling the in memory cache services.AddMemoryCache(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { var fileProvider = new PhysicalFileProvider(env.ContentRootPath); app.Run(async context => { //getting the cache object here var cache = context.RequestServices.GetService<IMemoryCache>(); var greeting = cache.Get(CACHE_KEY) as string; }); } } public class Program { public static void Main(string[] args) { var host = new WebHostBuilder() .UseKestrel() .UseStartup<Startup>() .Build(); host.Run(); } } }

答案 1 :(得分:0)

这样的结果会产生相同的结果

val diff = for {
  firstInner <- first
  v1 <- firstInner
  secondInner <- second
  v2 <- secondInner
} yield if (v1 != v2) s"$v2}"

println(diff2 mkString ", ") // prints 23, 45

但如果数组大小不同,那么这个过程会因IndexOutOfBoundsException而失败。