RosettaCodeData/Task/Stem-and-leaf-plot/Erlang/stem-and-leaf-plot.erl
2026-04-30 12:34:36 -04:00

131 lines
4.1 KiB
Erlang

%%% ============================================================
%%% Stem-and-Leaf Plot in Erlang
%%% ============================================================
%%% - Pure functions
%%% - No mutation
%%% - Deterministic transformations
%%% - Explicit functional pipeline
%%% ============================================================
-module(stem_leaf).
-export([main/0]).
%%% ============================================================
%%% 1. Mathematical Helpers (Pure Functions)
%%% ============================================================
%% expand_number/1
%% Conceptually expands single digit numbers to two-digit
%% (e.g., 7 -> 07). Numerically unchanged, but included
%% for semantic clarity.
expand_number(N) ->
N.
%% stem/1
%% Returns the stem (all but the last digit).
%% Example: 127 -> 12
stem(N) ->
N div 10.
%% leaf/1
%% Returns the leaf (last digit).
%% Example: 127 -> 7
leaf(N) ->
N rem 10.
%% range/2
%% Returns a list of integers from From to To (inclusive).
%% Used to guarantee stems 0..14 are always present.
range(From, To) when From =< To ->
lists:seq(From, To).
%%% ============================================================
%%% 2. Data Transformation Pipeline
%%% ============================================================
%% build_stem_leaf/1
%% Takes raw data and returns a list of:
%% [{Stem, [SortedLeaves]}, ...]
%%
%% Steps:
%% 1. Expand numbers
%% 2. Sort entire dataset
%% 3. Generate all stems 0..14
%% 4. Collect and sort leaves for each stem
build_stem_leaf(Data) ->
Expanded = [expand_number(N) || N <- Data],
Sorted = lists:sort(Expanded),
Stems = range(0, 14),
[{S, sorted_leaves(S, Sorted)} || S <- Stems].
%% sorted_leaves/2
%% Filters all numbers matching a given stem
%% Extracts leaves
%% Sorts leaves
sorted_leaves(StemValue, Data) ->
Leaves =
[leaf(N) || N <- Data, stem(N) =:= StemValue],
lists:sort(Leaves).
%%% ============================================================
%%% 3. Formatting Functions (Pure Rendering Layer)
%%% ============================================================
%% format_stem/1
%% Formats stem as two digits (leading zero if needed).
%% Example: 7 -> "07"
format_stem(S) ->
io_lib:format("~2..0B", [S]).
%% format_leaves/1
%% Converts list of integers into space-separated string.
%% Example: [1,3,7] -> "1 3 7"
format_leaves([]) ->
"";
format_leaves(Leaves) ->
string:join([integer_to_list(L) || L <- Leaves], " ").
%% render_line/1
%% Converts {Stem, Leaves} into formatted line.
%% Example:
%% {12, [3,4,7]} -> "12 | 3 4 7"
render_line({StemValue, Leaves}) ->
lists:flatten(
io_lib:format("~s | ~s",
[format_stem(StemValue), format_leaves(Leaves)])
).
%% render_plot/1
%% Converts full stem-leaf structure into multi-line string.
render_plot(StemLeafPairs) ->
Lines = [render_line(Pair) || Pair <- StemLeafPairs],
string:join(Lines, "\n").
%%% ============================================================
%%% 4. Program Entry Point
%%% ============================================================
main() ->
%% --------------------------------------------------------
%% Raw Dataset
%% --------------------------------------------------------
Data = [
12,127,28,42,39,113,42,18,44,118,44,37,113,124,37,48,127,36,29,31,
125,139,131,115,105,132,104,123,35,113,122,42,117,119,58,109,23,
105,63,27,44,105,99,41,128,121,116,125,32,61,37,127,29,113,121,
58,114,126,53,114,96,25,109,7,31,141,46,13,27,43,117,116,27,7,
68,40,31,115,124,42,128,52,71,118,117,38,27,106,33,117,116,111,
40,119,47,105,57,122,109,124,115,43,120,43,27,27,18,28,48,125,
107,114,34,133,45,120,30,127,31,116,146
],
%% --------------------------------------------------------
%% Functional Processing Pipeline
%% --------------------------------------------------------
StemLeafStructure = build_stem_leaf(Data),
Plot = render_plot(StemLeafStructure),
%% --------------------------------------------------------
%% Output
%% --------------------------------------------------------
io:format("~s~n", [Plot]).