Home > Software engineering >  Split One Row into many based on splitting string in multiple cells
Split One Row into many based on splitting string in multiple cells

Time:04-06

Trying to split one row into many based on string in two cells. it is similar to the question LINQ to separate column value of a row to different rows in .net but i need to split based on Product & Cost Columns rather than product column only

SNo. Product Cost
1 colgate,closeup,pepsodent 50,100,150
2 rin,surf 100

into

SNo. Product Cost
1 colgate 50
1 closeup 100
1 pepsodent 150
2 rin 100
2 surf 100

I'm using Linq to Object with Entity Framework

CodePudding user response:

Try the following. Since you have not presented any model it can be inaccurate in names.

var loaded = ctx.Products.ToList();

var query = 
    from p in loaded
    from sp in p.Product.Split(',').Zip(p.Cost.Split(','), (p, c) => (p, c))
    select new 
    {
        Sno = p.Sno,
        Product = sp.p,
        Cost = sp.c
    };

var splitted = query.ToList(); 

CodePudding user response:

Using @SvyatoslavDanyliv naming, here is an answer:

var loaded = ctx.Products.ToList();

var query = 
    from p in loaded
    from sp in p.Product.Split(',').Zip(p.Cost.Split(','), (p, c) => (p, c))
    select new 
    {
        Sno = p.Sno,
        Product = sp.p,
        Cost = sp.c
    };

var splitted = query.ToList(); 

It feels a bit complicated to me. I would prefer using an extension method to create a variant of Zip that repeats the last element of a shorter sequence to match the longer sequence:

public static class EnumerableExt {
    public static IEnumerable<(T1 First,T2 Second)> ZipExtend<T1,T2>(this IEnumerable<T1> s1, IEnumerable<T2> s2) {
        var s1e = s1.GetEnumerator();
        var s2e = s2.GetEnumerator();

        T1 s1eLast = default;
        T2 s2eLast = default;
        bool has_s2 = false;
        if (s1e.MoveNext()) {
            do {
                s1eLast = s1e.Current;
                if (s2e.MoveNext()) {
                    s2eLast = s2e.Current;
                    has_s2 = true;
                }
                else if (!has_s2)
                    yield break;
                yield return (s1eLast, s2eLast);
            } while (s1e.MoveNext());
            if (has_s2)
                while (s2e.MoveNext())
                    yield return (s1eLast, s2e.Current);
        }

        yield break;
    }
}

Then the answer is:

var query = 
    from p in loaded
    from pr in p.Product.Split(',').ZipExtend(p.Cost.Split(','))
    select new 
    {
        Sno = p.Sno,
        Product = pr.First,
        Cost = pr.Second
    };

var splitted = query.ToList();
  • Related