Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
处理不同类型的列表-使用scala(或函数式编程)比Java更昂贵吗?_Java_Scala_Functional Programming - Fatal编程技术网

处理不同类型的列表-使用scala(或函数式编程)比Java更昂贵吗?

处理不同类型的列表-使用scala(或函数式编程)比Java更昂贵吗?,java,scala,functional-programming,Java,Scala,Functional Programming,首先,让我澄清一下,我对Scala和函数式编程非常陌生,因此我的理解和实现可能不正确或效率低下 给定如下所示的文件: type1 param11 param12 ... type2 param21 param22 ... type2 param31 param32 ... type1 param41 param42 ... ... public void parse(List[Type1] type1s, List[Type2] type2s, List[String] lines) {

首先,让我澄清一下,我对Scala和函数式编程非常陌生,因此我的理解和实现可能不正确或效率低下

给定如下所示的文件:

type1 param11 param12 ...
type2 param21 param22 ...
type2 param31 param32 ...
type1 param41 param42 ...
...
public void parse(List[Type1] type1s, List[Type2] type2s, List[String] lines) {
    for (String line in lines) {
        if (line.startsWith("type1")) {
            Type1 type1 = Type1.createObj(line);
            type1s.add(type1)l
        } else if (line.startsWith("type2")) {
            Type2 type2 = Type2.createObj(line);
            type2s.add(type2)l
        } else { throw new Exception("Unknown type %s".format(line)) }
    }
}
基本上,每一行都以对象的类型开始,该对象可以由同一行中的以下参数创建。我正在使用一个应用程序,它遍历每一行,创建一个给定类型的对象,并返回所有对象的列表

在Java中,我的实现如下:

type1 param11 param12 ...
type2 param21 param22 ...
type2 param31 param32 ...
type1 param41 param42 ...
...
public void parse(List[Type1] type1s, List[Type2] type2s, List[String] lines) {
    for (String line in lines) {
        if (line.startsWith("type1")) {
            Type1 type1 = Type1.createObj(line);
            type1s.add(type1)l
        } else if (line.startsWith("type2")) {
            Type2 type2 = Type2.createObj(line);
            type2s.add(type2)l
        } else { throw new Exception("Unknown type %s".format(line)) }
    }
}
为了在Scala中执行相同的操作,我执行以下操作:

def parse(lines: List[String]): (List[Type1], List[Type2]) = {
    val type1Lines = lines filter (x => x.startsWith("type1"))
    val type2Lines = lines filter (x => x.startsWith("type2"))

    val type1s = type1Lines map (x => Type1.createObj(x))
    val type2s = type2Lines map (x => Type2.createObj(x))

    (type1s, type2s)
}
据我所知,虽然我的Java实现只遍历了列表一次,但Scala one必须执行三次:过滤type1、过滤type2和从中创建对象。这意味着Scala实现应该比Java实现慢,对吗?此外,Java实现也更节省内存,因为它只有3个实例:
type1s
type2s
。另一方面,Scala one有5条:
type1line
type2line
type1s
type2s

因此,我的问题是:

  • 有没有更好的方法重新编写Scala实现,使列表只迭代一次
  • 使用不可变对象意味着每次都要创建一个新对象,是吗 这意味着函数式编程比其他编程需要更多的内存
更新:我创建了一个简单的测试来证明Scala程序的速度较慢:一个程序收到一个大小为1000000的字符串列表。它遍历一个列表并检查每个项目,如果一个项目以“type1”开头,它将
1
添加到名为
type1s
的列表中,否则,它将
2
添加到另一个名为
type2s
的列表中

Java实现:

public static void test(List<String> lines) {
    System.out.println("START");
    List<Integer> type1s = new ArrayList<Integer>();
    List<Integer> type2s = new ArrayList<Integer>();
    long start = System.currentTimeMillis();
    for (String l : lines) {
        if (l.startsWith("type1")) {
            type1s.add(1);
        } else {
            type2s.add(2);
        }
    }
    long end = System.currentTimeMillis();

    System.out.println(String.format("END after %s milliseconds", end - start));
}
def test(lines: List[String]) = {
    println("START")
    val start = java.lang.System.currentTimeMillis()
    val type1Lines = lines filter (x => x.startsWith("type1"))
    val type2Lines = lines filter (x => x.startsWith("type2"))

    val type1s = type1Lines map (x => 1)
    val type2s = type2Lines map (x => 2)
    val end = java.lang.System.currentTimeMillis()

    println("END after %s milliseconds".format(end - start))
  }
}
Java应用程序平均需要44毫秒,而Scala应用程序则需要200毫秒

object ScalaTester extends App {
  val random = new Random
  test((0 until 1000000).toList map {_ => s"type${random nextInt 10}"})

  def test(lines: List[String]) {
    val start = Platform.currentTime
    val m = lines groupBy {
      case s if s startsWith "type1" => "type1"
      case s if s startsWith "type2" => "type2"
      case _ => ""
    }
    println(s"Total type1: ${m("type1").size}; Total type2: ${m("type2").size}; time=${Platform.currentTime - start}")
  }
}
Scala(以及一般的函数式编程)的真正优势在于能够处理将一种结构转换为另一种结构的数据。
当然,您可以在单个代码行中组合映射、平面映射、过滤器、组等。它导致一次数据收集。

每次都可以一个接一个地创建新集合。这确实会产生一点开销。但是有人在乎吗?尽管您创建了过多的集合,但Scala风格的编程可以帮助您设计面向并行的代码(正如Niklas已经提到的),并防止出现命令式编程容易出现的非常难以捉摸的副作用错误

,我认为您应该测试它是否足够快。如果您发现Scala版本太慢,您可以尝试使用单折叠而不是四折叠。如果这仍然很慢,您可以用Java编写一个方法,用Scala编写程序的其余部分。显然,纯数据结构有一定的开销,但通常您并不关心这一点,而是关心在编写代码时它给您带来的生产率提高,以及更容易将程序转换为并行程序的可能性design@NiklasB. 您好,我不是要对我的程序进行基准测试或比较它们的性能,我的意思是问,使用Scala是否会比使用Java产生更多的集合迭代。但是,当性能没有被证明是一个问题时,为什么还要关心它呢?另外,从技术上讲,你没有问它是否会导致多次传球,而是问你是否能在一次传球中做到,你可以,但是,这会使您的代码更难阅读,因此可能不值得费劲。想要在任意大小的文件或列表上迭代一次而不是四次,这是一个合理的愿望,无论绝对性能如何。@DaveNewton:我有一个deja vuHi,非常感谢,看起来您的代码比我的代码性能好得多:)但是,我真的不明白你的结论。这是否意味着使用函数式编程语言会在安全性/可伸缩性增益和性能成本之间进行权衡?当然不是。您可以以完美的性能获得完美、安全和可扩展的代码。这只取决于程序员!))虽然一般来说,由于处理器的命令性质,命令式代码被认为速度要快一点。您知道循环比递归更快,迭代可变集合处理比函数不可变列表遍历更快,等等。。。