Erlang如何获取产品记录的最高/最低价格并展示价格区间
如何从二进制价格的Erlang产品列表中提取价格区间
好问题!要实现从二进制格式的产品价格里提取「最低-最高」的区间,核心是不能直接比较二进制字符串(比如<<"100.00">>的二进制值会小于<<"99.99">>,因为ASCII码'1' < '9'),必须先转成可正确排序的数值类型,再处理极值后转回二进制格式。
以下是两种可靠的实现方案,分别适用于不同场景:
方案一:基于浮点数的快速实现(适用于非高精度要求场景)
这个方案简单直接,适合对精度要求不高的普通场景:
% 假设已提前定义product记录 -record(product, {amount :: binary()}). get_price_range(Products) -> % 1. 提取所有产品的二进制价格字段 AmountBinList = [P#product.amount || P <- Products], % 2. 把二进制字符串转成浮点数,用于数值比较 NumericAmounts = [binary_to_float(Bin) || Bin <- AmountBinList], % 3. 找出最小值和最大值 MinFloat = lists:min(NumericAmounts), MaxFloat = lists:max(NumericAmounts), % 4. 把浮点数转回保留两位小数的二进制字符串 MinBin = float_to_binary(MinFloat, [{decimals, 2}, compact]), MaxBin = float_to_binary(MaxFloat, [{decimals, 2}, compact]), % 5. 拼接成目标区间格式 <<MinBin/binary, " - ", MaxBin/binary>>. % 测试调用示例 Products = [#product{amount=<<"20.21">>}, #product{amount=<<"30.21">>}, #product{amount=<<"9.21">>}], get_price_range(Products). % 输出 <<"9.21 - 30.21">>
方案二:基于整数的高精度实现(推荐用于货币场景)
浮点数存在精度误差(比如0.1 + 0.2 = 0.30000000000000004),如果是处理货币类价格,建议把价格转成「分」为单位的整数,彻底避免精度问题:
-record(product, {amount :: binary()}). get_price_range(Products) -> AmountBinList = [P#product.amount || P <- Products], % 把二进制价格转成以分为单位的整数(比如<<"20.21">> → 2021) CentsList = [convert_to_cents(Bin) || Bin <- AmountBinList], MinCents = lists:min(CentsList), MaxCents = lists:max(CentsList), % 把整数转回二进制价格格式 MinBin = convert_to_price_bin(MinCents), MaxBin = convert_to_price_bin(MaxCents), <<MinBin/binary, " - ", MaxBin/binary>>. % 辅助函数:二进制价格转分 convert_to_cents(AmountBin) -> <<IntegerPart/binary, ".", DecimalPart/binary>> = AmountBin, % 处理小数位不足两位的情况(比如<<"5">> → <<"5.00">>) FixedDecimal = case byte_size(DecimalPart) of 1 -> <<DecimalPart/binary, "0">>; 2 -> DecimalPart; _ -> error(invalid_price_format) end, binary_to_integer(IntegerPart) * 100 + binary_to_integer(FixedDecimal). % 辅助函数:分转二进制价格 convert_to_price_bin(Cents) -> DollarPart = Cents div 100, CentPart = Cents rem 100, % 补零确保小数位是两位(比如9分 → "09") CentBin = if CentPart < 10 -> <<"0", (integer_to_binary(CentPart))/binary>>; true -> integer_to_binary(CentPart) end, <<(integer_to_binary(DollarPart))/binary, ".", CentBin/binary>>. % 测试调用示例 Products = [#product{amount=<<"20.21">>}, #product{amount=<<"30.21">>}, #product{amount=<<"9.21">>}], get_price_range(Products). % 输出 <<"9.21 - 30.21">>
额外注意事项
- 如果产品列表可能为空,建议在函数开头添加判断逻辑,比如返回默认值
<<"0.00 - 0.00">>或者抛出业务异常。 - 若存在非标准格式的价格(比如没有小数点、小数位超过两位),需要在转换函数中添加格式校验,避免运行时错误。
内容的提问来源于stack exchange,提问作者Jon Riel
相关产品推荐
相关产品推荐

