如何基于条件合并多版本相似列表并生成精简代码?
合并多版本列表生成精简代码结构
我有一个根据条件返回多个相似列表之一的函数,该代码由存储数据的Dictionary<int, List<string>>生成(生成器代码较为简单,故不提供实现)。
原始冗余代码
List<string> GetList(int version) { var list = new List<string>(); if (version == 1) { list.Add("A"); list.Add("B"); list.Add("C"); list.Add("D"); list.Add("E"); } if (version == 2) { list.Add("A"); list.Add("B"); list.Add("B2"); list.Add("B3"); list.Add("C"); list.Add("D"); list.Add("E"); } if (version == 3) { list.Add("A"); list.Add("B"); list.Add("B2"); list.Add("B3"); list.Add("D"); list.Add("E"); } if (version == 11) { list.Add("A"); list.Add("B"); list.Add("B2"); list.Add("B3"); list.Add("C"); list.Add("D"); list.Add("E"); } return list; }
当前代码存在大量重复数据,以上仅为简短示例。我希望生成的代码改为如下精简形式:
目标精简代码
List<string> GetList2(int version) { var list = new List<string>(); list.Add("A"); list.Add("B"); if (version >= 2) { list.Add("B2"); list.Add("B3"); } if (version <= 2 || version >= 11) { list.Add("C"); } list.Add("D"); list.Add("E"); return list; }
因此需要一个算法,能够将源Dictionary<int, List<string>>转换为适合生成上述精简代码的形式。
期望的算法接口
我设想的方法签名如下(注意使用了IEquatable<T>,实际列表成员实现了该接口,示例中使用字符串便于理解):
public class ListMerger { public static List<VersionedChunk<T>> Merge<T>(Dictionary<int, List<T>> input) where T : IEquatable<T> { throw new NotImplementedException(); } } public record VersionRange(int? MinVersion, int? MaxVersion); public record VersionedChunk<T>(List<T> Data, List<VersionRange> Versions) where T : IEquatable<T>;
单元测试用例
我已为Merge方法准备了如下单元测试:
[TestClass] public sealed class Test1 { [TestMethod] public void WhenNoVersions_ReturnEmptyList() { Dictionary<int, List<string>> input = []; var output = ListMerger.Merge(input); Assert.AreEqual(0, output.Count); } [TestMethod] public void WhenSingleVersion_ReturnSingleNonVersionedChunk() { Dictionary<int, List<string>> input = new() { [1] = ["A", "B", "C"] }; var output = ListMerger.Merge(input); Assert.AreEqual(1, output.Count); Assert.AreEqual(3, output[0].Data.Count); Assert.IsTrue(output[0].Data.SequenceEqual(["A", "B", "C"])); Assert.AreEqual(0, output[0].Versions.Count); } [TestMethod] public void WhenAllVersionsAreSame_ReturnSingleNonVersionedChunk() { Dictionary<int, List<string>> input = new() { [1] = ["A", "B", "C"], [2] = ["A", "B", "C"], }; var output = ListMerger.Merge(input); Assert.AreEqual(1, output.Count); Assert.AreEqual(3, output[0].Data.Count); Assert.IsTrue(output[0].Data.SequenceEqual(["A", "B", "C"])); Assert.AreEqual(0, output[0].Versions.Count); } [TestMethod] public void WhenElementIsAdded_ProduceVersionedChunk() { Dictionary<int, List<string>> input = new() { [1] = ["A", "B", "C"], [2] = ["A", "B", "B2", "C"], }; var output = ListMerger.Merge(input); Assert.AreEqual(3, output.Count); Assert.AreEqual(2, output[0].Data.Count); Assert.IsTrue(output[0].Data.SequenceEqual(["A", "B"])); Assert.AreEqual(0, output[0].Versions.Count); Assert.AreEqual(1, output[1].Data.Count); Assert.IsTrue(output[1].Data.SequenceEqual(["B2"])); Assert.AreEqual(1, output[1].Versions.Count); Assert.AreEqual(2, output[1].Versions[0].MinVersion); Assert.IsNull(output[1].Versions[0].MaxVersion); Assert.AreEqual(1, output[2].Data.Count); Assert.IsTrue(output[2].Data.SequenceEqual(["C"])); Assert.AreEqual(0, output[2].Versions.Count); } [TestMethod] public void WhenElementIsRemoved_ProduceVersionedChunk() { Dictionary<int, List<string>> input = new() { [1] = ["A", "B", "C"], [2] = ["A", "C"], }; var output = ListMerger.Merge(input); Assert.AreEqual(3, output.Count); Assert.AreEqual(1, output[0].Data.Count); Assert.IsTrue(output[0].Data.SequenceEqual(["A"])); Assert.AreEqual(0, output[0].Versions.Count); Assert.AreEqual(1, output[1].Data.Count); Assert.IsTrue(output[1].Data.SequenceEqual(["B"])); Assert.AreEqual(1, output[1].Versions.Count); Assert.IsNull(output[1].Versions[0].MinVersion); Assert.AreEqual(1, output[1].Versions[0].MaxVersion); Assert.AreEqual(1, output[2].Data.Count); Assert.IsTrue(output[2].Data.SequenceEqual(["C"])); Assert.AreEqual(0, output[2].Versions.Count); } [TestMethod] public void WhenElementIsRemovedAndAddedAgain_ProduceVersionedChunk() { Dictionary<int, List<string>> input = new() { [1] = ["A", "B", "C"], [2] = ["A", "C"], [3] = ["A", "B", "C"], }; var output = ListMerger.Merge(input); Assert.AreEqual(3, output.Count); Assert.AreEqual(1, output[0].Data.Count); Assert.IsTrue(output[0].Data.SequenceEqual(["A"])); Assert.AreEqual(0, output[0].Versions.Count); Assert.AreEqual(1, output[1].Data.Count); Assert.IsTrue(output[1].Data.SequenceEqual(["B"])); Assert.AreEqual(2, output[1].Versions.Count); Assert.IsNull(output[1].Versions[0].MinVersion); Assert.AreEqual(1, output[1].Versions[0].MaxVersion); Assert.AreEqual(3, output[1].Versions[1].MinVersion); Assert.IsNull(output[1].Versions[1].MaxVersion); Assert.AreEqual(1, output[2].Data.Count); Assert.IsTrue(output[2].Data.SequenceEqual(["C"])); Assert.AreEqual(0, output[2].Versions.Count); } [TestMethod] public void WhenElementIsAddedAndRemovedAgain_ProduceVersionedChunk() { Dictionary<int, List<string>> input = new() { [1] = ["A", "B"], [2] = ["A", "B", "C"], [3] = ["A", "B"], }; var output = ListMerger.Merge(input); Assert.AreEqual(2, output.Count); Assert.AreEqual(2, output[0].Data.Count); Assert.IsTrue(output[0].Data.SequenceEqual(["A", "B"])); Assert.AreEqual(0, output[0].Versions.Count); Assert.AreEqual(1, output[1].Data.Count); Assert.IsTrue(output[1].Data.SequenceEqual(["C"])); Assert.AreEqual(1, output[1].Versions.Count); Assert.AreEqual(2, output[1].Versions[0].MinVersion); Assert.AreEqual(2, output[1].Versions[0].MaxVersion); } [TestMethod] public void WhenElementsAreAddedAndRemoved_ProduceVersionedChunks() { Dictionary<int, List<string>> input = new() { [1] = ["A", "B", "C", "D", "E"], [2] = ["A", "B", "B2", "B3", "C", "D", "E"], [3] = ["A", "B", "B2", "B3", "D", "E"], [11] = ["A", "B", "B2", "B3", "C", "D", "E"], }; var output = ListMerger.Merge(input); Assert.AreEqual(4, output.Count); Assert.AreEqual(2, output[0].Data.Count); Assert.IsTrue(output[0].Data.SequenceEqual(["A", "B"])); Assert.AreEqual(0, output[0].Versions.Count); Assert.AreEqual(2, output[1].Data.Count); Assert.IsTrue(output[1].Data.SequenceEqual(["B2", "B3"])); Assert.AreEqual(1, output[1].Versions.Count); Assert.AreEqual(2, output[1].Versions[0].MinVersion); Assert.IsNull(output[1].Versions[0].MaxVersion); Assert.AreEqual(1, output[2].Data.Count); Assert.IsTrue(output[2].Data.SequenceEqual(["C"])); Assert.AreEqual(2, output[2].Versions.Count); Assert.IsNull(output[2].Versions[0].MinVersion); Assert.AreEqual(2, output[2].Versions[0].MaxVersion); Assert.AreEqual(11, output[2].Versions[1].MinVersion); Assert.IsNull(output[2].Versions[1].MaxVersion); Assert.AreEqual(2, output[3].Data.Count); Assert.IsTrue(output[3].Data.SequenceEqual(["D", "E"])); Assert.AreEqual(0, output[3].Versions.Count); } }
内容的提问来源于stack exchange,提问作者Dark Daskin
相关产品推荐
相关产品推荐

