I need to run validation on JSON input model by taking the value from one List and check if it exists in another. This value is a rating is from 1 - 5. If there is no matching number, then it should throw an error. Below is the code and this logic goes in the section commented with : //check if rating exist in score table
namespace Alpha.Model
{
// INPUT
public class AlphaCalcParamMethod
{
public ICollection<PortfolioInputModel> portfolios { get; set; }
public Setting settings { get; set; }
public bool Validation(ref string errString)
{
// Check if portfolio exists
if(portfolios == null || portfolios.Count < 1)
{
errString = "At least 1 Portfolio.";
return false;
}
//check if weight adds upto 1
foreach(var portfolio in portfolios)
{
// var holdings = new List<PortfolioHoldingInput>();
var weightAggregator = 0.00;
foreach(var holding in portfolio.portfolioHoldings)
{
weightAggregator += holding.fundWeight;
}
if (weightAggregator != 1)
{
errString = "Fund Weights should add upto 1";
}
return false;
}
//check if rating exist in score table
foreach(var portfolio in portfolios)
{
var holdings = new List<PortfolioHoldingInput>();
var scores = new List<Setting>();
foreach(var holding in holdings)
{
//fetch the value of fundRating double
foreach(var score in scores)
{
//check if the value above exist in grossAlpha's List fundRating
// if it doesn't return false
}
}
return false;
}
return true;
}
}
// OUTPUT
public class AlphaCalcResultMethod
{
public List<PortfolioOutputModel> portfolios { get; set; }
}
public class PortfolioInputModel
{
public string portfolioIdentifier { get; set; }
public ICollection<PortfolioHoldingInput> portfolioHoldings { get; set; }
}
public class PortfolioOutputModel
{
public string portfolioIdentifier { get; set; }
public double portfolioAlpha { get; set; }
public ICollection<PortfolioHoldingOutput> portfolioHoldings { get; set; }
}
public class PortfolioHoldingInput
{
public string fundIdentifier { get; set; }
public int fundRating { get; set; }
public double fundExpenseRatio { get; set; }
public double fundWeight { get; set; }
}
public class PortfolioHoldingOutput
{
public string fundIdentifier { get; set; }
public int fundRating { get; set; }
public double fundExpenseRatio { get; set; }
public double fundWeight { get; set; }
public double fundAlpha { get; set; }
}
public class Setting
{
public List<GrossAlpha> grossAlphas { get; set; }
}
public class GrossAlpha
{
public int fundRating { get; set; }
public double grossAlpha { get; set; }
}
}
If you are going to return additional values from method, you should use out parameters.
Don't specify type of variable in variable name. I.e. instead of errorString just use error. Hungarian notation and other tricks are not needed with modern IDEs.
Double type is not precise. You should avoid comparing it to integer values for equality. Prefer greater or less than comparisons.
Use LINQ to replace loops
Method name Validation is a noun. That is pretty confusing for method which is action and should a verb. Consider rename it to Validate or IsValid
Code
public bool IsValid(out string error)
{
if (portfolios?.Any() == false)
{
error = "At least 1 Portfolio.";
return false;
}
if (portfolios.Any(p => p.portfolioHoldings.Sum(h => h.fundWeight) < 1))
{
error = "Fund Weights should add upto 1";
return false;
}
var holdings = portfolios.SelectMany(p => p.portfolioHoldings);
var validRatings = new List<int> { 1, 2, 3, 4, 5 };
if (holdings.Any(h => !validRatings.Contains(h.fundRating)))
{
error = "Fund ratings should be in " + String.Join(",", validRatings);
return false;
}
error = "";
return true;
}
Note: if valid ratings are sequential numbers, then you can just check range of fundRating value:
if (holdings.Any(h => h.fundRating < 1 || 5 < h.fundRating))
Look this code:
if(!score.grossAlphas.Exists(x => x.fundRating == holding.fundRating))
{
return false;
}
it check if exists grossAlphas with fundRating equals holding.fundRating.
put it in the loop where you want to check, let me know if it is what you want and if it works.
Related
I want to compare all of my list of generic T property value to my local variable searchText.
i already try:
x.GetType().GetProperties().All(props => props.GetValue(x).ToString().ToLower().Contains(searchText.ToLower()))
and i get error : NullReferenceException: Object reference not set to an instance of an object.
here my full method :
protected List<T> ProcessCollection<T>(List<T> lstElements, IFormCollection requestFormData, Func<T, IComparable> getProp)
{
string searchText = string.Empty;
Microsoft.Extensions.Primitives.StringValues tempOrder = new[] { "" };
if (requestFormData.TryGetValue("search[value]", out tempOrder))
{
searchText = requestFormData["search[value]"].ToString();
}
var skip = Convert.ToInt32(requestFormData["start"].ToString());
var pageSize = Convert.ToInt32(requestFormData["length"].ToString());
if (requestFormData.TryGetValue("order[0][column]", out tempOrder))
{
var columnIndex = requestFormData["order[0][column]"].ToString();
var sortDirection = requestFormData["order[0][dir]"].ToString();
tempOrder = new[] { "" };
if (requestFormData.TryGetValue($"columns[{columnIndex}][data]", out tempOrder))
{
var columName = requestFormData[$"columns[{columnIndex}][data]"].ToString();
if (pageSize > 0)
{
var prop = GetProperty<T>(columName);
if (sortDirection == "asc")
{
return lstElements.Where(x=>x.GetType().GetProperties().All(props => props.GetValue(x).ToString().ToLower().Contains(searchText.ToLower()))
.Skip(skip).Take(pageSize).OrderBy(b => prop.GetValue(b)).ToList();
}
else
return lstElements
.Where(x => getProp(x).ToString().ToLower().Contains(searchText.ToLower()))
.Skip(skip).Take(pageSize).OrderByDescending(b => prop.GetValue(b)).ToList();
}
else
return lstElements;
}
}
return null;
}
this is how i call my method :
var listItem = ProcessCollection<Jtabel>(temp,requestFormData,x=>x.Name);
the temp that i pass to method already filled
and this is the class type that i pass to this method
public class Jtabel : BaseModel
{
public string Creator { get; set; }
public string Name { get; set; }
public int SO { get; set; }
public int SOD { get; set; }
public int SAP { get; set; }
public int BA { get; set; }
public int Invoice { get; set; }
public int EPD { get; set; }
public double DP { get; set; }
}
i will try to explain more detail as much i can, so i want to get all of my property from Jtabel class to my ProcessCollection where inside the method all of Jtable property will test each element that's contain searchText.
I am trying to add an InventoryState to the various products extended from my IProduct interface I created before, but the foreach() statement I made to check the state of the inventory is not changing the default value of Unassigned on the property...
This is the properties for each product object:
public string ProductType
{
get { return "Apple"; }
set { }
}
public double BulkPrice
{
get { return 0.99; }
set { }
}
public double RetailPrice
{
get { return 1.49; }
set { }
}
public int Quantity
{
get { return 50; }
set { }
}
public int MaxQuantity
{
get { return 100; }
set { }
}
public InventoryState Status
{
get { return InventoryState.Unassigned; }
set { }
}
And these are the various declarations and the foreach in question:
public enum InventoryState
{
Full,
Selling,
Stocking,
Empty,
Unassigned
}
public interface IProduct
{
string ProductType { get; set; }
double BulkPrice { get; set; }
double RetailPrice { get; set; }
int Quantity { get; set; }
int MaxQuantity { get; set; }
InventoryState Status { get; set; }
}
public static IProduct[] ProductList =
{
new Apple(),
new Blueberry()
};
foreach (IProduct productName in ProductList) // broken- not being called :(?
{
if (productName.Quantity == productName.MaxQuantity)
{
productName.Status = InventoryState.Full;
return productName.Status;
}
else if (productName.Quantity <= (productName.MaxQuantity * (0.5)))
{
productName.Status = InventoryState.Stocking;
}
else if (productName.Quantity == 0)
{
productName.Status = InventoryState.Empty;
}
else
{
productName.Status = InventoryState.Selling;
}
}
You always do in your automatic properties
get { return "some value";}
Even if you assign a value to it, it will always return "some value" even if the underlying value is different.
Do this for all your properties:
public string ProductType
{
get; set;
} = "Apple";
They will have default value "Apple" but it will get assigned and returned correctly.
Note that auto property default value is only from C# 6.0 onward.
Otherwise you need a private backing field.
I have this class:
public class Test
{
public string Id { get; set; }
public int Number { get; set; }
public int DoubleNumber { get; set; }
}
and a list
List<Test> myTestList;
How can I make the value of the field DoubleNumber in myTestList equal to twice the value of Number? Note that I am okay to create another list if that's needed.
If I understand your question correctly:
foreach(Test item in myList) {
item.DoubleNumber = 2*item.Number;
}
Or, if it's ok, just remove the setter and modify the getter to return 2x Number:
public class Test
{
public string Id { get; set; }
public int Number { get; set; }
public int DoubleNumber { get { return 2* this.Number; } } //completely remove setter
}
Or, if you still want to be able to modify DoubleNumber:
public class Test {
private int m_num;
private int m_doubleNum;
public string Id {
get;
set;
}
public int Number {
get {
return this.m_num;
}
set {
this.m_num = value;
this.m_doubleNum = 2 * value; //when Number is set, update m_doubleNum too
}
}
public int DoubleNumber {
get {
return this.m_doubleNum;
}
set {
this.m_doubleNum = value; //allow manual setting of DoubleNumber
//or maybe also modify Number here?
//this.m_num = value / 2;
}
}
}
One way it could be using a foreach statement:
foreach(var item in myTestList)
{
item.DoubleNumber = 2*item.Number;
}
Another way it could be to use LINQ.
var result = myTestList.Select(test => new Test
{
test.Id,
test.Number,
DoubleNumber = 2*test.Number;
})
.ToList();
Among the two ways I would prefer the first one, since it's more clear what you are trying to do and more performant (in the second approach you have to create a new object for each object in myTestList).
I've the MyTableItem class that maps a DynamoDB table.
I need to implements the GetMyTableItemsWithoutFinalStatus method that query the table by specific filters on nested property of a custom type, MyStatus.
The filter has to check if:
there's no status
status is not initialized
there's no "final" status in the status list
date is greater than today - daysFromNow
So my conditions in OR are:
StatusCount == 0
Status == null
Status.Where(s => s.Status != StatusEnum.DELIVERED).Count == 0
Date > DateTime.UtcNow.AddDays(-daysFromNow)
Actually I need to get back all the items that has no status or no final status, because I've to update them.
How can I implement the condition on nested property of MyStatus object?
This is my code
[Serializable]
public class MyTableItem
{
[DynamoDBHashKey]
public string Id { get; set; }
[DynamoDBProperty]
public string Field1 { get; set; }
[DynamoDBProperty]
public string Field2 { get; set; }
[DynamoDBProperty]
[DynamoDBGlobalSecondaryIndexRangeKey]
public DateTime Date { get; set; }
// My complex object
[DynamoDBProperty(typeof(MyStatusConverter))]
public MyStatus Status { get; set; }
[DynamoDBProperty]
public int StatusCount { get { return Status.Count; } set { value = Status.Count; } }
}
[Serializable]
public class MyStatus : IList<MyState>
{
private readonly IList<MyState> stateList = new List<MyState>();
public PeppolDespatchAdviceState this[int index]
{
get { return stateList[index]; }
set { stateList.Insert(index, value); }
}
public int Count
{
get { return stateList.Count; }
}
public bool IsReadOnly
{
get { return stateList.IsReadOnly; }
}
// IList interface implementation...
}
[Serializable]
public class MyState
{
public string DocumentType { get; set; }
public string Status { get; set; }
public string SkipCause { get; set; }
public DateTime Date { get; set; }
}
public enum StatusEnum
{
DEFAULT,
CREATED,
DELIVERED,
UNDELIVERABLE,
RE_RECEIVED
}
#region Converter definition
public class MyStatusConverter : IPropertyConverter
{
public DynamoDBEntry ToEntry(object value)
{
// Implementation...
}
public object FromEntry(DynamoDBEntry entry)
{
// Implementation...
}
#endregion
public IList<MyTableItem> GetMyTableItemsWithoutFinalStatus(long id, int daysFromNow = 3)
{
try
{
List<MyTableItem> items = new List<MyTableItem>();
DynamoDBOperationConfig operationConfig = new DynamoDBOperationConfig();
operationConfig.OverrideTableName = "MyTableName";
operationConfig.IndexName = "MyIndex";
List<ScanCondition> conditions = new List<ScanCondition>();
conditions.Add(new ScanCondition(MyTableItemTableAttributes.StatusCount, ScanOperator.Equal, 0));
conditions.Add(new ScanCondition(MyTableItemTableAttributes.Status, ScanOperator.IsNull));
// Here I need to add a LINQ condition: Status.Where(s => s.Status != StatusEnum.DELIVERED).Count == 0 )
conditions.Add(new ScanCondition(MyTableItemTableAttributes.Date, ScanOperator.GreaterThan, DateTime.UtcNow.AddDays(-daysFromNow)));
operationConfig.QueryFilter = conditions;
operationConfig.ConditionalOperator = ConditionalOperatorValues.Or;
DynamoDBContext context = new DynamoDBContext(DynamoDBClient);
items = context.Query<MyTableItem>(id, operationConfig).ToList();
return items;
}
catch (Exception ex)
{
throw;
}
}
I have a model structure as illustrate below.
public class GuideLineSectionsViewModel
{
public GuideLineSectionsViewModel()
{
SectionsSet = new List<SectionViewModel>();
}
public string Title { get; set; }
public List<SectionViewModel> SectionsSet { get; set; }
}
public class SectionViewModel
{
public SectionViewModel()
{
SectionsSet = new List<SectionViewModel>();
QuestionsSet = new List<QuestionViewModel>();
ProblemsSet = new List<ProblemViewModel>();
GoalsSet = new List<GoalViewModel>();
BarriersSet = new List<BarriersViewModel>();
QuestionReferencesSet = new List<QuestionReferenceViewModel>();
}
public string Heading { get; set; }
public List<SectionViewModel> SectionsSet { get; set; }
public List<QuestionViewModel> QuestionsSet { get; set; }
public List<ProblemViewModel> ProblemsSet { get; set; }
public List<GoalViewModel> GoalsSet { get; set; }
public List<BarriersViewModel> BarriersSet { get; set; }
public List<QuestionReferenceViewModel> QuestionReferencesSet { get; set; }
}
public class ProblemViewModel
{
public string Text { get; set; }
public bool Identified { get; set; }
public List<GoalViewModel> GoalsSet { get; set; }
public List<QuestionReferenceViewModel> QuestionReferencesSet { get; set; }
}
Now Based on the condition I need to update the every list value of the ProblemViewModel using linq.Below is the condition
public GuideLineSectionsViewModel FindGuidelineType(GuideLineSectionsViewModel guidelineSectionModel)
{
//GuideLineSectionsViewModel result = new GuideLineSectionsViewModel();
string title = guidelineSectionModel.Title;
int count = Regex.Matches(title, "Low Intensity").Count;
if (count > 0)
{
}
return guidelineSectionModel;
}
The guidelineSectionModel.Title will contain the text as "some value : Low Intensity". So i used the regx to filter the text. Is there other way i can directly check the condition in linq. and update the model model.
I want to update list value of ProblemViewModelmodel property value public bool Identified to "true"
Currently it contain only False value.
Please can anyone help me to solve the issue.
Have a look at following method. I could not put LINQ but I think this answer can solve your purpose. Again Some classes structure are missing in your question so you may need to put that in following method.
GuideLineSectionsViewModel FindGuidelineType(GuideLineSectionsViewModel guidelineSectionModel)
{
//GuideLineSectionsViewModel result = new GuideLineSectionsViewModel();
string title = guidelineSectionModel.Title;
int count = Regex.Matches(title, "Low Intensity").Count;
if (count > 0)
{
foreach(SectionViewModel svm in guidelineSectionModel.SectionsSet)
{
foreach(ProblemViewModel pvm in svm.ProblemsSet)
{
pvm.Identified = true;
}
}
}
return guidelineSectionModel;
}
If you prefer LINQ:
if(guideLine.Title.Contains("Low Intensity"))
{
guideLine.SectionsSet.ForEach(s => s.ProblemsSet.ForEach(ps => ps.Identified = true));
}
Note: please read this answer https://stackoverflow.com/a/2962689/1525637 due to possible performance problems with the Regex.Matches, you should use String.Contains instead.