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; }
}
1 Answer 1
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(..)
);
-
1\$\begingroup\$ I hope you don't mind the edit ;-) \$\endgroup\$t3chb0t– t3chb0t2017年02月14日 10:42:12 +00:00Commented Feb 14, 2017 at 10:42
-
\$\begingroup\$ Not a problem. I appreciate the help! It seems you had a typo also! Haha \$\endgroup\$Svek– Svek2017年02月14日 10:59:50 +00:00Commented Feb 14, 2017 at 10:59
return
? I thought the function in the method declaration was a typo but there's more. Is this even working? \$\endgroup\$