(map和foreach的区别)Erlang编程入门之高端函数

本文介绍了Erlang中的函数式编程技巧,包括定义简单的函数、使用标准库函数如map和foreach处理列表,以及如何利用这些函数进行温度单位转换和排序。

http://tech.it168.com/jd/2008-01-30/200801302323777.shtml

Erlang和其他的函数式编程语言一样,有一些高端的函数,我们下面就来看看这部分的内容:

   90 > Xf = fun(X) -> X * 2 end.   #Fun    91 > Xf( 5 ).    10

  我们在这里定义了一个函数,其功能是将输入的数值乘以2. 于是我们调用Xf(5)得到结果10.两个在日常工作中有用的函数是 foreach和map,定义如下:

 

   foreach (Fun, [First | Rest]) ->   Fun(First),    foreach (Fun, Rest);    foreach (Fun, []) ->   ok.   map(Fun, [First | Rest]) ->   [Fun(First) | map(Fun,Rest)];   map(Fun, []) ->   [].

 

  这两个函数都在模块lists中。foreach需要一个列表作为输入,然后对每个列表元素应用一次fun函数。而map则创建一个新的列表来保存被fun函数作用过的列表元素。回到shell中,我们使用map 和fun对列表中的每个元素都加上3:

   92 > Add_3 = fun(X) -> X + 3 end.   #Fun    93 > lists:map(Add_3, [ 1 , 2 , 3 ]).   [ 4 , 5 , 6 ]

  现在让我们输出城市的温度列表:

   95 > Print_City = fun({City, {X, Temp}}) -> io:format( " ~-15w ~w ~w~n " ,   [City, X, Temp]) end.   #Fun    96 > lists: foreach (Print_City, [{moscow, {c, - 10 }}, {cape_town, {f, 70 }},   {stockholm, {c, - 4 }}, {paris, {f, 28 }}, {london, {f, 36 }}]).   moscow c - 10   cape_town f 70   stockholm c - 4   paris f 28   london f 36

  ok

  我们现在定义一个fun函数,来将列表中的华氏度全部转换为摄氏度:

   - module(tut13).    - export([convert_list_to_c / 1 ]).   convert_to_c({Name, {f, Temp}}) ->   {Name, {c, trunc((Temp - 32 ) * 5 / 9 )}};   convert_to_c({Name, {c, Temp}}) ->   {Name, {c, Temp}}.   convert_list_to_c(List) ->   lists:map(fun convert_to_c / 1 , List).    98 > tut13:convert_list_to_c([{moscow, {c, - 10 }}, {cape_town, {f, 70 }},   {stockholm, {c, - 4 }}, {paris, {f, 28 }}, {london, {f, 36 }}]).   [{moscow,{c, - 10 }},   {cape_town,{c, 21 }},   {stockholm,{c, - 4 }},   {paris,{c, - 2 }},   {london,{c, 2 }}]

  convert_to_c函数的功能和上面相同,只不过我们使用了一个fun:

  lists:map(fun convert_to_c/1, List)

  但我们使用一个某处定义的函数作为fun时,我们应该明确的知道它的方法名和参数数量(Function/Arity)。所以在map中我们写 lists:map(fun convert_to_c/1,List)。所以你可以看到 convert_list_to_c变短了,变得更加容易阅读理解了。

  标准模块lists同样包含了函数sort(Fun,List),这里的fun 带有两个参数。如果第一个参数小于第二个参数则fun应该返回true ,否则应该返回false。我们将其添加到convert_list_to_c中:

   - module(tut13).    - export([convert_list_to_c / 1 ]).   convert_to_c({Name, {f, Temp}}) ->   {Name, {c, trunc((Temp - 32 ) * 5 / 9 )}};   convert_to_c({Name, {c, Temp}}) ->   {Name, {c, Temp}}.   convert_list_to_c(List) ->   New_list = lists:map(fun convert_to_c / 1 , List),   lists:sort(fun({_, {c, Temp1}}, {_, {c, Temp2}}) - >   Temp1 < Temp2 end, New_list).    99 > c(tut13).   {ok,tut13}    100 > tut13:convert_list_to_c([{moscow, {c, - 10 }}, {cape_town, {f, 70 }},   {stockholm, {c, - 4 }}, {paris, {f, 28 }}, {london, {f, 36 }}]).   [{moscow,{c, - 10 }},   {stockholm,{c, - 4 }},   {paris,{c, - 2 }},   {london,{c, 2 }},   {cape_town,{c, 21 }}]

  在sort中我们使用fun:

  fun({_, {c, Temp1}}, {_, {c, Temp2}}) -> Temp1 < Temp2 end,

  这里我们引入了一个概念——匿名变量"_"(anonymous variable)。这是一种当获取一个值时的缩写的形式,但是我们将忽略这个值。我们可以在任何地方使用这个匿名特性,不仅仅是在fun 中。

<think>嗯,用户现在想了解Java或JavaScript中mapforEach方法的区别,特别是在集合操作中的用法。之前我回答过Kotlin的Lambda表达式集合操作,但用户这次转向JavaJS,需要调整重点。首先,我得回忆一下JavaJS中这两个方法的不同点。用户提供的引用资料里提到,JavaScript中的forEach返回undefined,不可链式调用,而map返回新数组。Java的Stream API里,map是中间操作,返回流,而forEach是终端操作,消费元素。这些是核心区别。需要分两部分来回答:JavaJavaScript各自的情况。然后对比它们的异同。要注意用户可能对两种语言都感兴趣,或者混淆了它们,所以要明确区分。 在Java部分,要提到Stream的mapforEach,以及它们的使用场景。比如map用于转换元素,返回新流;forEach是终端操作,用于副作用。例如,使用map将字符串转大写,再用forEach打印。 在JavaScript部分,强调forEach没有返回值,用于遍历执行操作,而map返回新数组,适合数据转换。比如用map生成新数组,用forEach进行日志输出。还要提到链式调用的问题,因为forEach返回undefined,不能链式调用map后的结果。 用户可能想知道为什么会有这样的设计差异,需要解释两者的用途不同。比如,函数编程中,map用于无副作用的转换,而forEach用于有副作用的操作。还要注意引用中的资料,比如引用[2]提到forEach返回undefined,引用[4][5]说明map、filter的区别。在回答中要自然引用这些内容,确保准确性。 用户可能对性能有疑问,但引用里提到性能最优的选择,不过具体数据需要谨慎处理,可能不在当前问题范围内,但可以简要提及。 最后,生成相关问题,引导用户深入,比如链式调用的影响、性能比较、设计思想等。确保问题与主题相关,帮助用户进一步学习。</think>### Java与JavaScript中mapforEach方法对比 --- #### 一、核心区别 | **特性** | **map** | **forEach** | |-----------------|----------------------------------|---------------------------------| | **返回值** | 返回新集合/流(保留操作结果) | 无返回值(`void`/`undefined`) | | **链式调用** | 支持(中间操作) | 不支持(终端操作)[^2] | | **副作用** | 应避免副作用(纯函数) | 专门用于执行副作用[^5] | | **集合类型** | 保持原集合类型(数组/流) | 不改变原集合类型 | --- #### 二、Java中的具体实现 ##### 1. Stream API用法 ```java // 示例集合 List<String> words = Arrays.asList("apple", "banana"); // map:转换元素类型并返回新流 List<Integer> lengths = words.stream() .map(s -> s.length()) // 中间操作 .collect(Collectors.toList()); // 终端操作 → [5,6] // forEach:消费元素(如打印) words.stream().forEach(s -> System.out.println(s)); // 终端操作[^1] ``` - **map特性**:可链式调用多个中间操作(如`filter`、`sorted`) - **forEach限制**:必须作为终端操作,会关闭流[^1] ##### 2. 集合类直接调用 ```java List<Integer> numbers = new ArrayList<>(List.of(1,2,3)); numbers.replaceAll(x -> x * 2); // 类似map的效果(直接修改原集合) numbers.forEach(x -> System.out.print(x)); // 副作用操作 ``` --- #### 三、JavaScript中的具体实现 ##### 1. 数组方法对比 ```javascript const arr = [1, 2, 3]; // map:生成新数组 const doubled = arr.map(x => x * 2); // [2,4,6],原数组不变[^4] // forEach:仅执行操作 arr.forEach(x => console.log(x)); // 输出1,2,3,返回undefined[^2] ``` ##### 2. 链式调用差异 ```javascript // 有效链式调用(map可连续) const result = arr.map(x => x + 1).filter(x => x > 2); // 无效链式调用(forEach返回undefined) arr.forEach(x => x * 2).filter(...); // TypeError[^5] ``` --- #### 四、关键应用场景 | **方法** | **适用场景** | **典型用例** | |-----------|-------------------------------------------------|---------------------------------| | `map` | 数据转换、类型映射、数学计算 | 提取对象属性、格式化数据[^4] | | `forEach` | 日志输出、DOM操作、外部状态修改 | 渲染UI组件、更新数据库[^2] | **Java示例**: ```java // 数据转换:字符串列表→长度列表 List<String> names = List.of("Alice", "Bob"); List<Integer> lengths = names.stream().map(String::length).toList(); ``` **JavaScript示例**: ```javascript // 副作用操作:更新DOM document.querySelectorAll('button').forEach(btn => { btn.addEventListener('click', handleClick); }); ``` --- #### 五、性能与设计哲学 1. **函数编程原则** - `map`遵循无副作用原则,适合纯函数场景 - `forEach`明确用于副作用,分离关注点[^5] 2. **内存效率** - `map`会创建新集合,大数据集需注意内存开销 - `forEach`直接遍历原集合,内存占用更低[^4] 3. **可读性对比** ```javascript // map表达"转换"意图更明确 const prices = products.map(p => p.price * taxRate); // forEach强调"执行动作" cartItems.forEach(item => updateInventory(item)); ``` --- ### 相关问题 1. 为什么JavaScript的`forEach`不能直接中断循环?如何实现类似`break`的效果? 2. Java Stream的`map`与`flatMap`在处理集合时有何本质区别? 3. 在函数编程中,为什么推荐优先使用`map`而不是`forEach`? 4. JavaScript的`for...of`循环与`forEach`方法在性能上有何差异? 5. 如何通过Java Stream的`peek`方法实现类似`forEach`的调试功能? --- ### 引用 [^1]: Java Stream API的中间操作与终端操作设计原理 [^2]: JavaScript中`forEach`方法返回值的限制与副作用特性 [^4]: `map`方法在数据转换场景中的性能优化策略 [^5]: 函数编程中无副作用原则对集合操作的影响
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值