Python函数:map()函数对序列批量应用操作
Python函数map()函数对序列批量应用操作一、开篇批处理的优雅方式假设你有一个列表需要对每个元素做同样的操作——比如把每个数字翻倍或者把每个字符串转成大写。用for循环当然可以但Python提供了更函数式、更简洁的方式map()。⌨️ 先看对比numbers[1,2,3,4,5]# 方法一for循环result1[]forninnumbers:result1.append(n*2)print(result1)# [2, 4, 6, 8, 10]# 方法二列表推导式result2[n*2forninnumbers]print(result2)# [2, 4, 6, 8, 10]# 方法三map()函数result3list(map(lambdan:n*2,numbers))print(result3)# [2, 4, 6, 8, 10] 三种方式都能完成任务但map()有其独特的优势它是惰性求值的返回迭代器可以处理无限序列可以同时处理多个序列并且在一些场景下比列表推导式更快。二、map()的基本用法2.1 语法和基本概念# map()的语法# map(function, iterable, ...)# function: 要应用到每个元素的函数# iterable: 一个或多个可迭代对象# 返回值: map对象迭代器不是列表# ⌨️ 基本使用defsquare(x):returnx**2numbers[1,2,3,4,5]resultmap(square,numbers)print(type(result))# class mapprint(result)# map object at 0x...print(list(result))# [1, 4, 9, 16, 25]# ⚠️ map对象是迭代器——只能遍历一次resultmap(square,numbers)print(list(result))# [1, 4, 9, 16, 25]print(list(result))# [] —— 第二次遍历为空迭代器已耗尽# 如果需要多次使用先转成列表resultlist(map(square,numbers))print(result)# [1, 4, 9, 16, 25]print(result)# [1, 4, 9, 16, 25] —— 列表可以多次访问2.2 map()配合内置函数# map()和内置函数是黄金搭档# 内置函数通常用C实现速度快# 类型转换str_numbers[1,2,3,4,5]int_numberslist(map(int,str_numbers))print(int_numbers)# [1, 2, 3, 4, 5]# 字符串处理words[ python , JAVA , rust ]cleanedlist(map(str.strip,words))print(cleaned)# [python, JAVA, rust]loweredlist(map(str.lower,cleaned))print(lowered)# [python, java, rust]# 计算长度word_lengthslist(map(len,lowered))print(word_lengths)# [6, 4, 4]# 取绝对值numbers[-5,3,-8,1,-2]abs_valueslist(map(abs,numbers))print(abs_values)# [5, 3, 8, 1, 2]# 计算ASCII码chars[a,b,c,A,B,C]ascii_codeslist(map(ord,chars))print(ascii_codes)# [97, 98, 99, 65, 66, 67]# ASCII码转回字符codes[72,101,108,108,111]letterslist(map(chr,codes))print(.join(letters))# Hello三、多序列并行处理3.1 多个可迭代对象# map()可以接收多个可迭代对象# function必须接收与可迭代对象数量相同的参数# 两个列表的元素相加a[1,2,3,4,5]b[10,20,30,40,50]sumslist(map(lambdax,y:xy,a,b))print(sums)# [11, 22, 33, 44, 55]# 使用内置函数 operator.addimportoperator sums2list(map(operator.add,a,b))print(sums2)# [11, 22, 33, 44, 55]# 三个列表x[1,2,3]y[4,5,6]z[7,8,9]productslist(map(lambdaa,b,c:a*b*c,x,y,z))print(products)# [28, 80, 162]# 实际应用合并多个数据源names[张三,李四,王五]scores[85,92,78]grades[B,A,C]# 格式化为字符串recordslist(map(lambdaname,score,grade:f{name}:{score}分({grade}),names,scores,grades))forrinrecords:print(r)# 张三: 85分(B)# 李四: 92分(A)# 王五: 78分(C)3.2 不等长序列的处理# ⚠️ map()以最短的可迭代对象为准——多余的被忽略a[1,2,3,4,5]b[10,20,30]# 只有3个元素resultlist(map(lambdax,y:xy,a,b))print(result)# [11, 22, 33] —— 只处理了前3对# 如果需要填充不足的部分使用 itertools.zip_longestfromitertoolsimportzip_longest a[1,2,3,4,5]b[10,20,30]# 用0填充不足的部分result2list(map(lambdapair:pair[0](pair[1]ifpair[1]isnotNoneelse0),zip_longest(a,b,fillvalue0)))# 更简单的写法result3[xyforx,yinzip_longest(a,b,fillvalue0)]print(result3)# [11, 22, 33, 4, 5]四、map() vs 列表推导式4.1 性能对比importtime# 准备数据numberslist(range(1_000_000))# 测试 map() 性能starttime.perf_counter()result_maplist(map(lambdax:x*21,numbers))map_timetime.perf_counter()-startprint(fmap():{map_time:.4f}秒)# 测试列表推导式性能starttime.perf_counter()result_listcomp[x*21forxinnumbers]listcomp_timetime.perf_counter()-startprint(f列表推导式:{listcomp_time:.4f}秒)# 测试 for 循环性能starttime.perf_counter()result_loop[]forxinnumbers:result_loop.append(x*21)loop_timetime.perf_counter()-startprint(ffor循环:{loop_time:.4f}秒)# 结果可能类似列表推导式 ≈ map for循环# 使用内置函数时map可能更快因为是C实现的starttime.perf_counter()result_builtinlist(map(abs,numbers))builtin_timetime.perf_counter()-startprint(fmap(内置函数):{builtin_time:.4f}秒)4.2 可读性对比和选型# 选型指南# ✅ 场景一简单的转换——列表推导式更可读numbers[1,2,3,4,5]squares[x**2forxinnumbers]# 清晰直观# ✅ 场景二使用内置函数——map()更简洁strings[1,2,3]intslist(map(int,strings))# 比 [int(s) for s in strings] 更简洁# ✅ 场景三需要条件过滤——列表推导式map filter很啰嗦numbers[1,2,3,4,5,6]even_squares[x**2forxinnumbersifx%20]# vseven_squares_maplist(map(lambdax:x**2,filter(lambdax:x%20,numbers)))# 列表推导式明显更清晰# ✅ 场景四多序列处理——mapoperator 简洁importoperator a[1,2,3]b[4,5,6]sumslist(map(operator.add,a,b))# vssums_lc[xyforx,yinzip(a,b)]# 两者都可以mapoperator稍微更函数式# 总结没有绝对的更好# - 简单转换 → 选你最舒服的# - 有过滤条件 → 列表推导式# - 用内置函数 → map()# - 多序列 → map() 或 zip列表推导式五、实战案例5.1 批量数据格式转换# 场景将API返回的字符串数据转为需要的格式# 模拟API返回的温度数据字符串带单位api_response[23.5°C,18.2°C,30.1°C,15.8°C,27.3°C]# 使用map进行流水线处理# 步骤1去掉单位# 步骤2转为浮点数# 步骤3摄氏度转华氏度# 步骤4格式化输出temps_c_strlist(map(lambdas:s.replace(°C,),api_response))temps_clist(map(float,temps_c_str))temps_flist(map(lambdac:c*9/532,temps_c))temps_f_strlist(map(lambdaf:f{f:.1f}°F,temps_f))print(temps_f_str)# [74.3°F, 64.8°F, 86.2°F, 60.4°F, 81.1°F]# 或者链式调用用生成器表达式更清晰defconvert_temperatures(raw_data):温度转换流水线# 每一步都是可理解的转换strippedmap(lambdas:s.rstrip(°C),raw_data)as_floatmap(float,stripped)to_fahrenheitmap(lambdac:c*9/532,as_float)formattedmap(lambdaf:f{f:.1f}°F,to_fahrenheit)returnlist(formatted)print(convert_temperatures(api_response))5.2 并行处理多个列的表格数据# 场景处理电子表格中的数据headers[姓名,数学,语文,英语]rows[[张三,85,92,78],[李四,90,88,95],[王五,76,85,82],]# 分别提取各列并转换类型nameslist(map(lambdarow:row[0],rows))math_scoreslist(map(lambdarow:int(row[1]),rows))chinese_scoreslist(map(lambdarow:int(row[2]),rows))english_scoreslist(map(lambdarow:int(row[3]),rows))# 计算每个学生的总分和平均分total_scoreslist(map(lambdam,c,e:mce,math_scores,chinese_scores,english_scores))avg_scoreslist(map(lambdat:round(t/3,1),total_scores))fori,nameinenumerate(names):print(f{name}: 总分{total_scores[i]}, 平均{avg_scores[i]})# 张三: 总分255, 平均85.0# 李四: 总分273, 平均91.0# 王五: 总分243, 平均81.0六、注意事项和总结# ⚠️ 注意1map返回的是迭代器不是列表resultmap(str.upper,[a,b,c])# 要转成列表才能多次访问result_listlist(result)# ⚠️ 注意2map是惰性求值的# 在list()调用之前函数还没有被实际执行resultmap(lambdax:print(x),[1,2,3])# 这里什么都不会打印还没求值list(result)# 现在才会打印 1 2 3# ⚠️ 注意3迭代器只能消费一次resultmap(str,[1,2,3])len1sum(1for_inresult)# 3len2sum(1for_inresult)# 0 ——迭代器已空核心要点map(func, iterable)对每个元素应用func返回迭代器惰性求值——只在需要时才计算节省内存多序列支持——可以同时处理多个可迭代对象搭配内置函数——map(int, ...)是最简洁的类型转换方式有过滤条件时用列表推导式——更可读✅map()是批处理数据的利器当需要对序列中每个元素做同样的操作时它是你的首选工具之一。