Run-length encoding: Difference between revisions

Content added Content deleted
(Added Zig)
Line 6,274: Line 6,274:
W11BW11B2W23BW13
W11BW11B2W23BW13
WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW
WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW
</pre>

=={{header|Zig}}==
<syntaxhighlight lang="zig">const std = @import("std");

fn Run(comptime T: type) type {
return struct {
value: T,
length: usize,
};
}

fn encode(
comptime T: type,
input: []const T,
allocator: std.mem.Allocator,
) ![]Run(T) {
var runs = std.ArrayList(Run(T)).init(allocator);
defer runs.deinit();

var previous: ?T = null;
var length: usize = 0;

for (input) |current| {
if (previous == current) {
length += 1;
} else if (previous) |value| {
try runs.append(.{
.value = value,
.length = length,
});
previous = current;
length = 1;
} else {
previous = current;
length += 1;
}
}

if (previous) |value| {
try runs.append(.{
.value = value,
.length = length,
});
}

return runs.toOwnedSlice();
}

test encode {
const input =
"WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW";

const expected = [_]Run(u8){
.{ .length = 12, .value = 'W' },
.{ .length = 1, .value = 'B' },
.{ .length = 12, .value = 'W' },
.{ .length = 3, .value = 'B' },
.{ .length = 24, .value = 'W' },
.{ .length = 1, .value = 'B' },
.{ .length = 14, .value = 'W' },
};

const allocator = std.testing.allocator;
const actual = try encode(u8, input, allocator);
defer allocator.free(actual);

try std.testing.expectEqual(expected.len, actual.len);
for (expected, actual) |e, a| {
try std.testing.expectEqual(e.length, a.length);
try std.testing.expectEqual(e.value, a.value);
}
}

fn decode(
comptime T: type,
runs: []const Run(T),
allocator: std.mem.Allocator,
) ![]T {
var values = std.ArrayList(T).init(allocator);
defer values.deinit();
for (runs) |r|
try values.appendNTimes(r.value, r.length);
return values.toOwnedSlice();
}

test decode {
const runs = [_]Run(u8){
.{ .length = 12, .value = 'W' },
.{ .length = 1, .value = 'B' },
.{ .length = 12, .value = 'W' },
.{ .length = 3, .value = 'B' },
.{ .length = 24, .value = 'W' },
.{ .length = 1, .value = 'B' },
.{ .length = 14, .value = 'W' },
};

const allocator = std.testing.allocator;
const decoded = try decode(u8, &runs, allocator);
defer allocator.free(decoded);

try std.testing.expectEqualStrings(
"WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW",
decoded,
);
}

pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer std.debug.assert(gpa.deinit() == .ok);

const allocator = gpa.allocator();
var input = std.ArrayList(u8).init(allocator);
defer input.deinit();

const stdout = std.io.getStdOut().writer();
const stdin = std.io.getStdIn().reader();
try stdout.print("Input: ", .{});
try stdin.streamUntilDelimiter(input.writer(), '\n', null);

const runs = try encode(u8, input.items, allocator);
defer allocator.free(runs);

try stdout.print("Encoded:\n", .{});
for (runs) |r|
try stdout.print(" {}\n", .{r});

const decoded = try decode(u8, runs, allocator);
defer allocator.free(decoded);

try stdout.print("Decoded: {s}\n", .{decoded});
}</syntaxhighlight>
{{out}}
<pre>
Input: WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW
Encoded:
run_length_encoding.Run(u8){ .value = 87, .length = 12 }
run_length_encoding.Run(u8){ .value = 66, .length = 1 }
run_length_encoding.Run(u8){ .value = 87, .length = 12 }
run_length_encoding.Run(u8){ .value = 66, .length = 3 }
run_length_encoding.Run(u8){ .value = 87, .length = 24 }
run_length_encoding.Run(u8){ .value = 66, .length = 1 }
run_length_encoding.Run(u8){ .value = 87, .length = 14 }
Decoded: WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW
</pre>
</pre>