阅读 897

总是在用List,来了解一波Sequence

前言

最近看到一个概念:Sequence。挺有意思。Google了一篇挺不错的文章,自己翻译了一下,贴出来大家一起“乐呵乐呵”。

原文地址(自备科学上网):medium.com/@elye.proje…

一、List

在我们开始讲述为什么Sequence更好(在某些情况下)之前,让我告诉你一些关于List的事情。

先看一段List与Iterator应用的代码:

val list = listOf(1, 2, 3, 4, 5, 6)
list.map{ it * 2 }.filter { it % 3  == 0 }.average()
复制代码

兢兢业业,一步步执行,为了更明显一点咱们打一点log。

val list = listOf(1, 2, 3, 4, 5, 6)
val result = list
        .map{ println("In Map"); it * 2 }
        .filter { println("In Filter");it % 3  == 0 }
println("Before Average")
println(result.average())
复制代码

看一下结果:

每一步都被执行了。似乎这没什么好奇怪的。但是我们来看个有趣的内容:Sequence

二、Sequence

2.1、普通使用

这里我们可以使用asSequence(),让我们的List转成一个Sequence。上代码:

val list = listOf(1, 2, 3, 4, 5, 6)
val result = list.asSequence()
        .map{ println("In Map"); it * 2 }
        .filter { println("In Filter");it % 3  == 0 }
println("Before Average")
println(result.average())
复制代码

看一下log结果:

Before Acerage被先打出来了。这就有意思了......换句话说,如果我们不调用average(),则不会对Sequence执行任何操作。

没错,它是懒惰的,只要不主动调用消费操作,Sequence就不会进行任何调用。(这一点有点类似于懒加载)

这时可能有小伙伴拎着40米的长刀:我tm就是要执行遍历,你给我来个懒加载是几个意思?

兄dei,刀放下,不要着急听我继续给你“吹”,不不不...继续给你唠。

我们不要只盯着懒加载,不知道有没有注意到它在In Map和In Filter中交错执行。 这意味着,它并非是先遍历执行完第一个集合然后再遍历执行完第二个集合。而是把多个遍历操作,打成一条链,遍历这个链…可能不好理解,咱们上个图:

2.2、Sequence优势

我猜大家依然n脸蒙蔽...咱们稍稍改改demo,第一个demo咱们先用List做对比:

val list = listOf(1, 2, 3, 4, 5, 6)
val result = list
        .map{ println("In Map $it"); it * 2 }
        .filter { println("In Filter $it");it % 3  == 0 }
println(result.first())
复制代码

调用first()方法。看一下log:

很正常。接下来咱们看一下“不正常”的Sequence:

val sequence = sequenceOf(1, 2, 3, 4, 5, 6)
val result = sequence
        .map{ println("In Map $it"); it * 2 }
        .filter { println("In Filter $it");it % 3  == 0 }
println(result.first())
复制代码

2.3、map对比

是不是看出Sequence的有趣之处了?其实Sequence的优化点在于map上,咱们继续进行一组测试:

val sequence = generateSequence(1) { it + 1 }.take(50000000)
val list = sequence.toList()

println("List Map Sum= " 
        + measureNanoTime { list.map { it * 2 }.sum() })
println("Sequence Map Sum " 
        + measureNanoTime { sequence.map { it * 2 }.sum() })

println("List Map Average " 
        + measureNanoTime { list.map { it * 2 }.average() })
println("Sequence Map Average " 
        + measureNanoTime { sequence.map { it * 2 }.average() })
复制代码

可以看出,在map下,Sequence要比List快4-7倍。但是,是不是Sequence就一定比List强呢?让我们换个操作符看一下:

2.4、filter对比

val sequence = generateSequence(1) { it + 1 }.take(50000000)
val list = sequence.toList()

println("List Filter Sum " 
        + measureNanoTime { list.filter { it % 3 == 0 }.sum() })
println("Sequence Filter Sum " 
        + measureNanoTime { sequence.filter { it % 3 == 0 }.sum() })

println("List Filter Average " 
        + measureNanoTime { list.filter { it % 3 == 0 }.average() })
println("Sequence Filter Average " 
        + measureNanoTime { sequence.filter { it % 3 == 0 }.average() })
复制代码

可以看出来,在filter中,List的表现要高于Sequence。

总结

  • 如果不需要额外操作符,使用List
  • 如果只有Map操作符,使用Sequence
  • 如果只有Filter操作符,使用List
  • 如果需要类似first()的操作符,可以酌情考虑使用Sequence。

我是一个应届生,最近和朋友们维护了一个公众号,内容是我们在从应届生过渡到开发这一路所踩过的坑,以及我们一步步学习的记录,如果感兴趣的朋友可以关注一下,一同加油~

个人公众号:咸鱼正翻身

关注下面的标签,发现更多相似文章
评论