none
Need help creating combinations RRS feed

  • Question

  • I have a bunch of attribute-value pairs in List<ProductOption> which looks like this:

    Attribute -- Value
    Color -- Red
    Color -- White
    Color -- Blue
    Size -- S
    Size -- M
    Size -- L
    Size -- XL

    I need to create combinations e.g. Red S, Red M, Red L, Red XL, White S, White, M, White L, White, XL, Blue S, Blue M, Blue L, Blue XL

    I understand that this can be done with LINQ with multiple FROMs. Could someone give me a hand with this?

    Thanks,

    Sam


    Thanks,
    Tuesday, May 18, 2010 2:36 AM

Answers

  • In that case, you can build the query at runtime based on a distinct list of attributes in the list. E.g.:

    List<ProductOption> attribsValues = new List<ProductOption>
    {
      new ProductOption { Attribute = "Color", Value = "Red" },
      new ProductOption { Attribute = "Color", Value = "Blue" },
      new ProductOption { Attribute = "Color", Value = "White" },
      new ProductOption { Attribute = "Size", Value = "S" },
      new ProductOption { Attribute = "Size", Value = "M" },
      new ProductOption { Attribute = "Size", Value = "L" },
      new ProductOption { Attribute = "Size", Value = "XL" },
      new ProductOption { Attribute = "Gender", Value = "Male" },
      new ProductOption { Attribute = "Gender", Value = "Female" },
      new ProductOption { Attribute = "Gender", Value = "Unknown" },
      new ProductOption { Attribute = "Gender", Value = "Both" }
    };
    
    //get distinct list of defined attributes
    IEnumerable<string> distinctAttributes = attribsValues.Select(a => a.Attribute).Distinct();
    
    //build query
    IQueryable<string> values = null;
    foreach (string attribute in distinctAttributes)
    {
      //make local copy of the attribute to reference in query where clause predicates
      string attribLocal = attribute;
    
      //query defined?
      if (values == null)
      {
        //first attribute, just get the values
        values = attribsValues.Where(av => av.Attribute == attribLocal).Select(v => v.Value).AsQueryable();
      }
      else
      {
        //subsequent attributes, append values for current attribute to query
        values = from ev in values
             from av in attribsValues.Where(av => av.Attribute == attribLocal).Select(v => v.Value).AsQueryable()
             select ev + " " + av;
      }
    }
    

    Kristofer - Huagati Systems Co., Ltd.
    Cool tools for Linq-to-SQL and Entity Framework:
    huagati.com/dbmltools (add-in with new features for the L2S and EF designers in VS2008 and VS2010)
    huagati.com/L2SProfiler (Query profiler for Linq-to-SQL and LLBLGen Pro)
    • Marked as answer by imsam67 Tuesday, May 18, 2010 3:15 PM
    Tuesday, May 18, 2010 4:47 AM
    Answerer

All replies

  • from c in Colors
    from s in Sizes
    select new { Color = c.Name, Size = s.Name }


    Kristofer - Huagati Systems Co., Ltd.
    Cool tools for Linq-to-SQL and Entity Framework:
    huagati.com/dbmltools (add-in with new features for the L2S and EF designers in VS2008 and VS2010)
    huagati.com/L2SProfiler (Query profiler for Linq-to-SQL and LLBLGen Pro)
    Tuesday, May 18, 2010 2:50 AM
    Answerer
  • KristoferA,

    Thanks for your response. I'm not a LINQ expert so please excuse my ignorance if I'm misinterpreting your solution. I think in your solution there are two separate lists, is that right? In my case, I only have one ProductOptions list and all the data is in there.

    How do I do the same thing if all the data is in one "container"?

    Or am I totally misunderstanding your solution?

    Thanks,

    Sam


    Thanks,
    Tuesday, May 18, 2010 2:59 AM
  • Sorry, I didn't read your question properly at first... :)

    from c in productOptionsList.Where(ca => ca.Attribute == "Color")
    from s in productOptionsList.Where(sa => sa.Attribute == "Size")
    select new { Color = c.Value, Size = s.Value };


    Kristofer - Huagati Systems Co., Ltd.
    Cool tools for Linq-to-SQL and Entity Framework:
    huagati.com/dbmltools (add-in with new features for the L2S and EF designers in VS2008 and VS2010)
    huagati.com/L2SProfiler (Query profiler for Linq-to-SQL and LLBLGen Pro)
    Tuesday, May 18, 2010 3:28 AM
    Answerer
  • KristoferA,

    Thanks again. This is much closer but here's the problem: This code requires me to know exactly what to expect i.e. Attribute will be either Color or Size. In my case, there may be many attributes and each product may have a different number of attributes e.g. one product may only have color, another may have color and size, yet another may have color, size and gender.

    Having said this, how can I make this code flexible enough that regardless of the number of attributes and the number of possible values for those attributes, I can still generate a combination of the items in my ProductOptions list?

    Again, thank you very much for your help.

    Sam


    Thanks,
    Tuesday, May 18, 2010 3:58 AM
  • In that case, you can build the query at runtime based on a distinct list of attributes in the list. E.g.:

    List<ProductOption> attribsValues = new List<ProductOption>
    {
      new ProductOption { Attribute = "Color", Value = "Red" },
      new ProductOption { Attribute = "Color", Value = "Blue" },
      new ProductOption { Attribute = "Color", Value = "White" },
      new ProductOption { Attribute = "Size", Value = "S" },
      new ProductOption { Attribute = "Size", Value = "M" },
      new ProductOption { Attribute = "Size", Value = "L" },
      new ProductOption { Attribute = "Size", Value = "XL" },
      new ProductOption { Attribute = "Gender", Value = "Male" },
      new ProductOption { Attribute = "Gender", Value = "Female" },
      new ProductOption { Attribute = "Gender", Value = "Unknown" },
      new ProductOption { Attribute = "Gender", Value = "Both" }
    };
    
    //get distinct list of defined attributes
    IEnumerable<string> distinctAttributes = attribsValues.Select(a => a.Attribute).Distinct();
    
    //build query
    IQueryable<string> values = null;
    foreach (string attribute in distinctAttributes)
    {
      //make local copy of the attribute to reference in query where clause predicates
      string attribLocal = attribute;
    
      //query defined?
      if (values == null)
      {
        //first attribute, just get the values
        values = attribsValues.Where(av => av.Attribute == attribLocal).Select(v => v.Value).AsQueryable();
      }
      else
      {
        //subsequent attributes, append values for current attribute to query
        values = from ev in values
             from av in attribsValues.Where(av => av.Attribute == attribLocal).Select(v => v.Value).AsQueryable()
             select ev + " " + av;
      }
    }
    

    Kristofer - Huagati Systems Co., Ltd.
    Cool tools for Linq-to-SQL and Entity Framework:
    huagati.com/dbmltools (add-in with new features for the L2S and EF designers in VS2008 and VS2010)
    huagati.com/L2SProfiler (Query profiler for Linq-to-SQL and LLBLGen Pro)
    • Marked as answer by imsam67 Tuesday, May 18, 2010 3:15 PM
    Tuesday, May 18, 2010 4:47 AM
    Answerer
  • Kristofer,

    Thank you very much. This is indeed what I was looking for. Thank you!!!

    Sam


    Thanks,
    Tuesday, May 18, 2010 3:15 PM
  • Kristofer,

    At the risk of being pushy, I have to ask you another question:

    The last you gave me does exactly what I need. Now, I want to add one more feature to it:

    As I generate these names, I also want to capture their underlying attributes. For example:

    One of the SKUs generated would be Red, L, Male. I also would like to capture that:

    the attributes for Red, L, Male are:

    • Color -- Red
    • Size -- M
    • Gender -- Male
    In order to handle this I created a SKU object which looks like this:
    private int intSKU;
    private string strProductName;
    private List<ProductOption> listProductAttributes = new List<ProductOption>();
    
    public int SKU
    {
      get { return intSKU; }
      set { intSKU = value;}
    }
    
    public string ProductName
    {
      get { return strProductName; }
      set { strProductName= value;}
    }
    
    public List<ProductOption> ProductAttributes
    {
      get { return listOptions ; }
      set { listOptions = value;}
    }
    This would allow me to do two things: Generate the SKU and capture its underlying attributes.

    So my question is how do I capture both?

    Thanks,

    Sam


    Thanks,
    Tuesday, May 18, 2010 4:03 PM