0
\$\begingroup\$

I am writing code to filter data on basis of attribute values. It is possible that the user can select multiple values.

How can this be better?

Models.Products filter(ViewModel.Filter search,IEnumerable<Models.Products> product)
{
 if (search.filter!= null && search.filter.Count>0)
 {
 var f = search.First();
 var tempProducts = products
 .Where(c => c.productattributes
 .Where(a => a.AttributeId == f.Id && f.Value.Contains(a.Value))
 .Any());
 search.filter.Remove(f);
 foreach (var fs in search)
 {
 var p = products.Where(c => c.productattributes.Where(a => a.AttributeId == fs.Id && fs.Value.Contains(a.Value)).Any());
 tempProducts = tempProducts.Union(p);
 }
 products = tempProducts;
 }
}

Filter View Model:

public class Filters
{
 public long Id { get; set; }
 public IEnumerable<string> Value { get; set; }
}
t3chb0t
44.6k9 gold badges84 silver badges190 bronze badges
asked Feb 13, 2017 at 20:31
\$\endgroup\$
1
  • \$\begingroup\$ Where's the return? I thought the function in the method declaration was a typo but there's more. Is this even working? \$\endgroup\$ Commented Feb 14, 2017 at 7:40

1 Answer 1

2
\$\begingroup\$

Your code appears to be incomplete but I've provided some ideas below.

Filters Class

I'm looking at your Filters class:

public class Filters
{
 public long Id { get; set; }
 public IEnumerable<string> Value { get; set; }
}

From this, I am assuming that the purpose of this is to hold the Attribute Id (key) and Search Keywords (value). So, I would propose you just use a Dictionary<long, List<string>> -- note that I changed the type of your Search Keywords to a List as I am not seeing any reason within your code example as to why it should/would need to be an IEnumberable type.

That would then change the method:

  • Method renamed
  • Parameter updated to use Dictionary instead (per above)

Here is the updated method

public IEnumerable<Product> FilterProductsByAttributeId(
 Dictionary<long, List<string>> filters,
 IEnumerable<Product> products)
{
 // your method contents here
}

Filter Method

I'm not sure why you have a complicated initializer for your tempProducts, but maybe it can be improved to something like this?

public IEnumerable<Product> FilterProductsByAttributeId(Dictionary<long, List<string>> filters, IEnumerable<Product> products)
{
 if (products == null) throw new ArgumentNullException(nameof(products));
 if (filters == null) throw new ArgumentNullException(nameof(filters));
 IEnumerable<Product> result = new List<Product>();
 foreach (var f in filters)
 {
 result = result.Union(products.Where(p => p.ProductAttributes
 .Where(a => a.AttributeId == f.Key && f.Value.Contains(a.Value)).Any()));
 }
 return result; 
}

Alternatively you can use the Aggregate extension:

return 
 filters
 .Aggregate(
 new List<Product>(), 
 (current, next) => current.Union(..)
 );
answered Feb 14, 2017 at 4:55
\$\endgroup\$
2
  • 1
    \$\begingroup\$ I hope you don't mind the edit ;-) \$\endgroup\$ Commented Feb 14, 2017 at 10:42
  • \$\begingroup\$ Not a problem. I appreciate the help! It seems you had a typo also! Haha \$\endgroup\$ Commented Feb 14, 2017 at 10:59

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.