From dddbd2f511f505ad4018ba007f065ea2b4ec8f79 Mon Sep 17 00:00:00 2001 From: Mikhail Popov Date: Fri, 8 Oct 2021 00:37:50 +0200 Subject: [PATCH 1/2] std.mem: Add functions to find the index of the mimimum/maximum value in a slice. --- lib/std/mem.zig | 52 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 5c0e3b30b76e..a69d1dcda04d 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -2143,6 +2143,7 @@ fn testWriteIntImpl() !void { /// Returns the smallest number in a slice. O(n). /// `slice` must not be empty. pub fn min(comptime T: type, slice: []const T) T { + assert(slice.len > 0); var best = slice[0]; for (slice[1..]) |item| { best = math.min(best, item); @@ -2151,12 +2152,15 @@ pub fn min(comptime T: type, slice: []const T) T { } test "mem.min" { - try testing.expect(min(u8, "abcdefg") == 'a'); + try testing.expectEqual(min(u8, "abcdefg"), 'a'); + try testing.expectEqual(min(u8, "bcdefga"), 'a'); + try testing.expectEqual(min(u8, "a"), 'a'); } /// Returns the largest number in a slice. O(n). /// `slice` must not be empty. pub fn max(comptime T: type, slice: []const T) T { + assert(slice.len > 0); var best = slice[0]; for (slice[1..]) |item| { best = math.max(best, item); @@ -2165,7 +2169,51 @@ pub fn max(comptime T: type, slice: []const T) T { } test "mem.max" { - try testing.expect(max(u8, "abcdefg") == 'g'); + try testing.expectEqual(max(u8, "abcdefg"), 'g'); + try testing.expectEqual(max(u8, "gabcdef"), 'g'); + try testing.expectEqual(max(u8, "g"), 'g'); +} + +/// Returns the index of the smallest number in a slice. O(n). +/// `slice` must not be empty. +pub fn indexOfMin(comptime T: type, slice: []const T) usize { + assert(slice.len > 0); + var best = slice[0]; + var index: usize = 0; + for (slice[1..]) |item, i| { + if (item < best) { + best = item; + index = i + 1; + } + } + return index; +} + +test "mem.indexOfMin" { + try testing.expectEqual(indexOfMin(u8, "abcdefg"), 0); + try testing.expectEqual(indexOfMin(u8, "bcdefga"), 6); + try testing.expectEqual(indexOfMin(u8, "a"), 0); +} + +/// Returns the index of the largest number in a slice. O(n). +/// `slice` must not be empty. +pub fn indexOfMax(comptime T: type, slice: []const T) usize { + assert(slice.len > 0); + var best = slice[0]; + var index: usize = 0; + for (slice[1..]) |item, i| { + if (item > best) { + best = item; + index = i + 1; + } + } + return index; +} + +test "mem.indexOfMax" { + try testing.expectEqual(indexOfMax(u8, "abcdefg"), 6); + try testing.expectEqual(indexOfMax(u8, "gabcdef"), 0); + try testing.expectEqual(indexOfMax(u8, "a"), 0); } pub fn swap(comptime T: type, a: *T, b: *T) void { From 100b8a244cdbcd16669e6b81ab82d6a628559e22 Mon Sep 17 00:00:00 2001 From: Mikhail Popov Date: Fri, 22 Oct 2021 14:38:08 +0200 Subject: [PATCH 2/2] Add std.mem.minMax() and std.mem.IndexOfMinMax() For finding the minimum and maximum values (and indices) in a slice in a single pass. --- lib/std/mem.zig | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index a69d1dcda04d..6d5ae952eb9e 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -2174,6 +2174,26 @@ test "mem.max" { try testing.expectEqual(max(u8, "g"), 'g'); } +/// Finds the smallest and largest number in a slice. O(n). +/// Returns an anonymous struct with the fields `min` and `max`. +/// `slice` must not be empty. +pub fn minMax(comptime T: type, slice: []const T) struct { min: T, max: T } { + assert(slice.len > 0); + var minVal = slice[0]; + var maxVal = slice[0]; + for (slice[1..]) |item| { + minVal = math.min(minVal, item); + maxVal = math.max(maxVal, item); + } + return .{ .min = minVal, .max = maxVal }; +} + +test "mem.minMax" { + try testing.expectEqual(minMax(u8, "abcdefg"), .{ .min = 'a', .max = 'g' }); + try testing.expectEqual(minMax(u8, "bcdefga"), .{ .min = 'a', .max = 'g' }); + try testing.expectEqual(minMax(u8, "a"), .{ .min = 'a', .max = 'a' }); +} + /// Returns the index of the smallest number in a slice. O(n). /// `slice` must not be empty. pub fn indexOfMin(comptime T: type, slice: []const T) usize { @@ -2216,6 +2236,34 @@ test "mem.indexOfMax" { try testing.expectEqual(indexOfMax(u8, "a"), 0); } +/// Finds the indices of the smallest and largest number in a slice. O(n). +/// Returns an anonymous struct with the fields `index_min` and `index_max`. +/// `slice` must not be empty. +pub fn indexOfMinMax(comptime T: type, slice: []const T) struct { index_min: usize, index_max: usize } { + assert(slice.len > 0); + var minVal = slice[0]; + var maxVal = slice[0]; + var minIdx: usize = 0; + var maxIdx: usize = 0; + for (slice[1..]) |item, i| { + if (item < minVal) { + minVal = item; + minIdx = i + 1; + } + if (item > maxVal) { + maxVal = item; + maxIdx = i + 1; + } + } + return .{ .index_min = minIdx, .index_max = maxIdx }; +} + +test "mem.indexOfMinMax" { + try testing.expectEqual(indexOfMinMax(u8, "abcdefg"), .{ .index_min = 0, .index_max = 6 }); + try testing.expectEqual(indexOfMinMax(u8, "gabcdef"), .{ .index_min = 1, .index_max = 0 }); + try testing.expectEqual(indexOfMinMax(u8, "a"), .{ .index_min = 0, .index_max = 0 }); +} + pub fn swap(comptime T: type, a: *T, b: *T) void { const tmp = a.*; a.* = b.*;