/// <summary> /// Filter items by feature. /// </summary> /// <param name="items">Input items to filter.</param> /// <param name="featureToAsk">Selected feature which is was asked.</param> /// <param name="value">Value which user put. If type of feature is numeric, then this value will be median.</param> /// <param name="index">Valid only in numerics type. If user select under median, the index is 0 otherwise 1.</param> /// <returns>Filtered items.</returns> public async Task <IEnumerable <PimItem> > FilterItemsByFeature( IEnumerable <PimFeature> allFeatures, IEnumerable <PimItem> items, FeatureToAsk featureToAsk, string value, int index = -1) { var pimItemResult = new List <PimItem>(); switch (featureToAsk.Type) { case FeatureType.Alphanumeric: foreach (var item in items) { var features = await _featuresService.GetFeaturesByNoAsync(item.No, allFeatures); var filteredItem = features.Where(i => i.Number == featureToAsk.Number).ToList(); if (filteredItem.Count() == 0) { pimItemResult.Add(item); } else { if (filteredItem[0].Value == value) { pimItemResult.Add(item); } } } return(pimItemResult); case FeatureType.Numeric: // Special case for Unit Price if (featureToAsk.Number == Constants.UnitPriceType) { if (index == 0) { return(items.Where(i => Convert.ToDouble(i.Unit_Price) <= Convert.ToDouble(value)).ToList()); } else if (index == 1) { return(items.Where(i => Convert.ToDouble(i.Unit_Price) > Convert.ToDouble(value)).ToList()); } } foreach (var item in items) { var features = await _featuresService.GetFeaturesByNoAsync(item.No, allFeatures); var filteredItem = features.Where(i => i.Number == featureToAsk.Number).ToList(); if (filteredItem.Count() == 0) { pimItemResult.Add(item); } else { if (index == 0) { if (double.Parse(filteredItem[0].Value, CultureInfo.InvariantCulture) <= double.Parse(value, CultureInfo.InvariantCulture)) { pimItemResult.Add(item); } } if (index == 1) { if (double.Parse(filteredItem[0].Value, CultureInfo.InvariantCulture) > double.Parse(value, CultureInfo.InvariantCulture)) { pimItemResult.Add(item); } } } } return(pimItemResult); default: return(items); } }
/// <summary> /// Method choose from inputs items features to ask. It's sorts features by order and computed information gain. /// </summary> /// <param name="items">List of items.</param> /// <returns>Ordered features to ask.</returns> public async Task <List <FeatureToAsk> > GetAllFeaturesToAsk(IEnumerable <PimItem> items) { var features = await _featuresService.GetAllFeaturesByItemAsync(); var itemsNos = items.ToList().Select(i => i.No).ToList(); var featuresByInputItems = features.Where(f => itemsNos.Contains(f.Key)).ToList(); var featureToAsks = new List <FeatureToAsk>(); foreach (var feature in featuresByInputItems) { List <string> added = new List <string>(); foreach (var ftr in feature.Value) { // Check if already in feature to ask var index = featureToAsks.FindIndex(f => f.Number == ftr.Number); if (!(index >= 0)) { // Add to feature to ask var featureToAsk = new FeatureToAsk(ftr.Number, ftr.Description, ftr.Order, ftr.Unit_Shorthand_Description); featureToAsk.ValuesList = new HashSet <string>(); // Added new feature value if (ftr.Value != string.Empty) { added.Add(ftr.Description); featureToAsk.ValuesList.Add(ftr.Value); } featureToAsks.Add(featureToAsk); } else { // Check if same item doesnt content same attribut if (!added.Contains(ftr.Description)) { if (ftr.Value != string.Empty) { added.Add(ftr.Description); featureToAsks[index].ValuesList.Add(ftr.Value); } } } } } // Added to features to ask the unit price which is by default not in features var unitPriceFeature = new FeatureToAsk(Constants.UnitPriceType, Messages.UnitPrice, 1, string.Empty); unitPriceFeature.ValuesList = new HashSet <string>(); foreach (var item in items) { unitPriceFeature.ValuesList.Add(item.Unit_Price.ToString("F", CultureInfo.CreateSpecificCulture("en-US"))); } featureToAsks.Add(unitPriceFeature); // Features without value or with one value are meaningless - they don't help var filteredFeatureToAsk = featureToAsks.Where(i => i.ValuesList.Count > 1).ToList(); // Set type of feature - numeric, text, etc filteredFeatureToAsk.ForEach(i => i.SetAndCheckType()); // For every feature compute information gain filteredFeatureToAsk.ForEach(i => i.ComputeInformationGain(items.ToList())); // Order features by Order and information gain var orderedFeaturesToAsk = filteredFeatureToAsk .OrderByDescending(i => i.Order) .ThenByDescending(i => i.InformationGain) .ToList(); return(orderedFeaturesToAsk); }