簡體   English   中英

C# LINQ 將復雜的連接字符串數據拆分為對象列表

[英]C# LINQ split complex joined string data to a List of objects

我有兩個這樣的課程:

class SomeObject_source
{
    public string Model;
    public string Color;
    public string Size;
}

class SomeObject_target
{
    public string Model;
    public string Color;
    public string Size;
    public double Quantity;
    public double Nett;
}

然后我們得到一個具有以下數據結構的SomeObject_source實例:

    SomeObject_source someObject_source = new SomeObject_source
    {
        Model = "Model_1|Model_2|Model_3|Model_4|Model_5",
        Color = "Black|Black|White|Blue|Red",
        Size = "S^1^0.5|M^2^1.0|L^1^0.6|S^3^1.5|S^1^0.6"
    };

Size 字符串具有以下模式: size^quantity^nett 但有時有一個 object 有一個簡單的數據,如:

    SomeObject_source someObject_source = new SomeObject_source
    {
        Model = "Model_1",
        Color = "Black",
        Size = "S"
    };

我試圖弄清楚如何優雅的單個 LINQ 查詢將以下數據拆分為 SomeObject_target 列表,以便結果等於:

    List<SomeObject_target> someObject_Target_List = new List<SomeObject_target>
    {
        new SomeObject_target
        {
            Model = "Model_1",
            Color = "Black",
            Size = "S",
            Quantity = 1,
            Nett = 0.5
        },
        new SomeObject_target
        {
            Model = "Model_2",
            Color = "Black",
            Size = "M",
            Quantity = 2,
            Nett = 1
        },
        new SomeObject_target
        {
            Model = "Model_3",
            Color = "White",
            Size = "L",
            Quantity = 1,
            Nett = 0.6
        },
        new SomeObject_target
        {
            Model = "Model_4",
            Color = "Blue",
            Size = "S",
            Quantity = 3,
            Nett = 1.5
        },
        new SomeObject_target
        {
            Model = "Model_5",
            Color = "Red",
            Size = "S",
            Quantity = 1,
            Nett = 0.6
        },
    };

現在我正在做如下:

    char Delimeter_main = '|';
    char Delimeter_inner = '^';
    List<SomeObject_target> someObject_Target_List_ = new List<SomeObject_target>();
    for (int ind = 0; ind < someObject_source.Model.Split(Delimeter_main).Count(); ind++)
    {
        string Model = someObject_source.Model.Split(Delimeter_main)[ind];
        string Color = someObject_source.Color.Split(Delimeter_main)[ind];
        string Size_unparsed = someObject_source.Size.Split(Delimeter_main)[ind];
        if (Size_unparsed.Contains(Delimeter_inner))
        {
            string size = Size_unparsed.Split(Delimeter_inner)[0];
            double quantity = double.TryParse(Size_unparsed.Split(Delimeter_inner)[1], out double _quantity) ? _quantity : 1;
            double nett = double.TryParse(Size_unparsed.Split(Delimeter_inner)[2], out double _nett) ? _nett : 1;
            someObject_Target_List_.Add(new SomeObject_target
            {
                Model = Model,
                Color = Color,
                Size = size,
                Quantity = quantity,
                Nett = nett
            });
        }
        else
        {
            someObject_Target_List_.Add(new SomeObject_target
            {
                Model = Model,
                Color = Color,
                Size = Size_unparsed,
                Quantity = 1,
                Nett = 1
            });
        }
    }

但這顯然看起來很奇怪,以及整體的數據架構。 是否有任何 LINQ 查詢可以在單個優雅查詢中完成?

正常可枚舉。Zip

var result = someObject_source.Model.Split(Delimeter_main)
    .Zip(someObject_source.Color.Split(Delimeter_main), (x, y) => new { x, y })
    .Zip(someObject_source.Size.Split(Delimeter_main), (zip1, z) =>
    {
        var secondSplit = z.Split(Delimeter_inner);
        return new SomeObject_target
        {
            Model = zip1.x,
            Color = zip1.y,
            Size = secondSplit[0],
            Quantity = double.TryParse(secondSplit[1], out double _quantity) ? _quantity : 1,
            Nett = double.TryParse(secondSplit[2], out double _nett) ? _nett : 1,
        };
    });

擴展方法Zip on 3 collection

更具可讀性,沒有第一個 Zip 結果的匿名 object 包裝器。

var results = someObject_source.Model.Split(Delimeter_main)
    .ZipThree(
        someObject_source.Color.Split(Delimeter_main),
        someObject_source.Size.Split(Delimeter_main), 
        (x, y, z) => {
            var secondSplit = z.Split(Delimeter_inner);
            return new SomeObject_target
            {
                Model = x,
                Color = y,
                Size = secondSplit[0],
                Quantity = double.TryParse(secondSplit[1], out double _quantity) ? _quantity : 1,
                Nett = double.TryParse(secondSplit[2], out double _nett) ? _nett : 1,
            };                    
        }
    );

使用這個以IEnumerable<IEnumerable<T>>為中心的Pivot擴展方法(注意:這不是特別有效,但更好/更快的方法要長得多):

public static class IEnumerableExt {
    // Pivot IEnumerable<IEnumerable<T>> by grouping matching positions of each sub-IEnumerable<T>
    // itemGroups - source data
    public static IEnumerable<IEnumerable<T>> Pivot<T>(this IEnumerable<IEnumerable<T>> itemGroups) =>
        itemGroups.Select(g => g.Select((item, i) => (item, i)))
                  .SelectMany(g => g)
                  .GroupBy(ii => ii.i, si => si.item);
}

您可以按如下方式處理someObject_source

char Delimeter_main = '|';
char Delimeter_inner = '^';

var someObject_Target_List =
    new[] {
        someObject_source.Model.Split(Delimeter_main),
        someObject_source.Color.Split(Delimeter_main),
        someObject_source.Size.Split(Delimeter_main)
    } // Create IEnumerable<string>[] (== IEnumerable<IEnumerable<string>>)
    .Pivot()
    .Select(t => t.ToList()) // project to IEnumerable<List<string>> to access members
    .Select(t => (model: t[0], color: t[1], rest: t[2].Split(Delimeter_inner))) // project to IEnumerable<ValueTuple> to access members
    .Select(t => new SomeObject_target {
        Model = t.model,
        Color = t.color,
        Size = t.rest[0],
        Quantity = t.rest.Length > 1 ? double.Parse(t.rest[1]) : default(double),
        Nett = t.rest.Length > 2 ? double.Parse(t.rest[2]) : default(double),
    })
    .ToList();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM