列表生成的三种方式比较(原生语法、流、DSL)

51 篇文章 5 订阅

列表生成的三种方式比较(原生语法、流、DSL)

概述

列表生成是平时开发中经常遇到的小功能。例如,生成一个0到n的列表,根据已有列表过滤一些元素来生成新列表等等。这样的问题一般几行或者十几行代码就处理掉了,也没有去注意。最近学习 Python 列表生成式的特性,在看到示例时联想到以前用 Java 和 Common Lisp 解决这类问题的方式,就写下本文来比较和总结各种方式的特点和优劣。

三种方式

  1. Python 列表生成式:Python中的列表生成式是在原生语法上对列表生成提供支持;
  2. Java Stream 类:Java 8 中引入的 Stream 相关类是 Stream API 在 JVM 平台的一种实现;
  3. Common Lisp 的 loop 宏:loop 宏虽然是 ANSI 标准中就提供的宏,但是也可以自行编写出来,它用一种更接近英语的形式来表达你的程序,然后这个形式被翻译成 Lisp,属于一类内部 DSL。

示例

  1. 生成1-10的列表:

    Python 的列表生成式:

    list(range(1, 11))
    

    Java 的 Stream:

    IntStream.range(1,11).boxed().collect(Collectors.toList())
    

    Common Lisp 的 loop 宏:

    (loop for i from 1 to 10 collect i)
    
  2. 生成1-10的平方和

    Python 的列表生成式:

    [x * x for x in range(1, 11)]
    

    Java 的 Stream:

    IntStream.range(1,11).map(i -> i*i)
        .boxed().collect(Collectors.toList())
    

    Common Lisp 的 loop 宏:

    (loop for i from 1 to 10 collect (* i i))
    
  3. 生成1-10的偶数的平方和

    Python 的列表生成式:

    [x * x for x in range(1, 11) if x % 2 == 0]
    

    Java 的 Stream:

    IntStream.range(1,11).filter(i -> i % 2 == 0).map(i -> i*i)
        .boxed().collect(Collectors.toList());
    

    Common Lisp 的 loop 宏:

    (loop for i from 1 to 10 when (evenp i) collect (* i i))
    
  4. 生成"abc"和"xyz"排列组合

    Python 的列表生成式:

    [m + n for m in 'ABC' for n in 'XYZ']
    

    Java 的 Stream:

    "abc".chars().mapToObj(i -> (char) i).flatMap(c1 -> 
      "xyz".chars().mapToObj(i -> (char) i).map(c2 -> c1.toString() + c2)).collect(Collectors.toList())
    

    Common Lisp 的 loop 宏:

    (loop for c1 across "abc" append 
      (loop for c2 across "xyz" collect (coerce (list c1 c2) 'string)))
    

总结

  1. Python 的列表生成式是专门针对这类问题的语法,采用了最少的字符,在语法层面解决这个问题,看起来是最优雅的。但是降低了语法的一致性,提高了语法的复杂度; 另外学习成本不高,不过由于其只能解决特定问题,且扩展性有限,因此学习的性价比也不是很高。
  2. Java 的 Stream 相关类是 Stream API 的 Java 实现,主要用于处理序列和数据流,刚好也可以用来解决这类问题。由于是在类和方法层面实现,因此可以有多种实现(例如,RxJava),开发者也可以根据需要实现自己的 Stream 库,扩展性较强;其次,因为 Stream 是一个相对通用的概念,很多语言都有自己的实现(或者第三方库实现),学习成本稍高(最好懂函数式编程),但是学习的性价比很高。但是因为 Java 对函数式编程的支持不那么好,Java 对 Stream API 的实现使用起来并不是那么舒服且略微有些繁琐。
  3. Common Lisp 中的 loop 宏是用宏实现的内部DSL,主要用于处理循环逻辑,也可以用来处理这类问题。DSL所带来的表达上的优势是非常明显的;另外宏是 Lisp 提供的基本特性,开发者可以根据自己的需要来编写自己的 loop 宏,可见扩展性也是不错的。但是DSL的维护门槛却是当下很难避免的缺点(好在loop宏已经成为标准的一部分)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值