c# - Searching for a combination within a list - c#

I have the following:
public class Address{
public string Number { get; set; }
public string Street { get; set; }
public string Suburb { get; set; }
}
List<Address> MyAddressList = new List<Address>();
Address MyAddress = new Address();
myAddress.Number = "5"
myAddress.Street = "Smith St"
myAddress.Suburb = "Smithsville"
MyAddressList.Add(MyAddress);
Address MyAddress2 = new Address();
myAddress2.Number = "10"
myAddress2.Street = "John St"
myAddress2.Suburb = "Johnsville"
MyAddressList.Add(MyAddress2);
string [] StreetToFind = new string {"Smith St"};
string [] SuburbToFind = new string {"Smithsville"};
string [] secondSuburbToFind = new string {"Johnsville"};
I want to search through this list and look for a combination of values and return a bool if the combination is found.
To start, I can search for an individual value in the Street Property:
bool StreetIsFound = MyAddressList.Select(x => x.Street).Intersect(StreetToFind).Any();
and the same for Suburb:
bool SuburbIsFind = = MyAddressList.Select(x => x.Suburb).Intersect(SuburbToFind).Any();
but I want to be able to search for both in a combination (bool StreetandSuburbFound)
so that if I searched for StreetToFind and SuburbToFind, StreetandSuburbFound would be true but would be false if searching for StreetToFind and secondSuburbToFind.

You can do this all with one call to Any. Like this
var isFound = MyAddressList.Any(x => StreetToFind.Contains(x.Street) && SuburbToFind.Contains(x.Suburb));
Or in query syntax
var isFound =
(from x in MyAddressList
where StreetToFind.Contains(x.Street)
&& SuburbToFind.Contains(x.Suburb)
select x)
.Any();

Or the method chain version of p.s.w.g's code:
MyAddressList.Any(x => StreetToFind.Contains(x.Street)
&& SuburbToFind.Contains(x.Suburb))
(obviously tweak as neccessary with the Contains etc)

Related

Filter based on a string value in List<string> column in a table Entity Framework Core

I have a table with the following structure (code first approach using Entity Framework Core) in PostgreSQL
public class Product_Order
{
[Key]
public string product_number { get; set; }
public string customer_product_number { get; set; }
public List<string> product_statuses { get; set; }
public bool is_test { get; set; } = false;
public DateTime created_at { get; set; } = DateTime.UtcNow;
public DateTime updated_at { get; set; } = DateTime.UtcNow;
public string created_by { get; set; } = "system";
public string updated_by { get; set; } = "system";
}
Now, the product_statuses column usually contains of a list of statuses - ready, pickedup, scheduled, closed, cancelled.
I need to come up with a solution which returns me a list of product orders which DOES NOT CONTAIN orders which are closed or cancelled.
Here's the solution that I have at the moment which is not filtering as expected
_context.Product_Order.Where(t => t.is_test && !t.statuses.Contains("closed") && !t.statuses.Contains("cancelled")).ToList();
I think your code is ok for your data structure to find that information. I have created a dummy class and list to replicate your data and list. And I was able to find data by using you code. Sample Code given below what I have tested =>
void Test()
{
List<Product_Order> items = new List<Product_Order>();
var temp = new Product_Order() { product_number = "001", isTest = true };
temp.product_statuses = new List<string>();
temp.product_statuses.Add("good");
temp.product_statuses.Add("greate");
temp.product_statuses.Add("new");
items.Add(temp);
temp = new Product_Order() { product_number = "002", isTest = true };
temp.product_statuses = new List<string>();
temp.product_statuses.Add("good");
temp.product_statuses.Add("bad");
temp.product_statuses.Add("notnew");
items.Add(temp);
temp = new Product_Order() { product_number = "003", isTest = true };
temp.product_statuses = new List<string>();
temp.product_statuses.Add("n/a");
temp.product_statuses.Add("bad");
temp.product_statuses.Add("Closed");
items.Add(temp);
temp = new Product_Order() { product_number = "004", isTest = false };
temp.product_statuses = new List<string>();
temp.product_statuses.Add("n/a");
temp.product_statuses.Add("bad");
temp.product_statuses.Add("Cancelled");
items.Add(temp);
var finalOutput = items.Where(c => c.isTest == true && !c.product_statuses.Where(v => v.ToLower() == "closed").Any() && !c.product_statuses.Where(v => v.ToLower() == "cancelled").Any()).ToArray();
}
public class Product_Order
{
public string product_number { get; set; }
public bool isTest { get; set; }
public List<string> product_statuses { get; set; }
}
Finally , I think it is your data what not wright with you lambda expression. So, I modified for you a little bit.And that is
FINAL ANSWER:
var finalOutput = _context.Product_Order.Where(c => c.isTest == true && !c.product_statuses.Where(v => v.ToLower() == "closed").Any() && !c.product_statuses.Where(v => v.ToLower() == "cancelled").Any()).ToArray();
Please check my code and let me know.

Regular Expression Not Equal is not working in C# string array

I researched this and cannot figure out why ?! doesn't do a Not Equal in my code.
The code has this :
var policyOne = "C";
var policyTwo = "GF1";
var policyThree = "018"
string policyNumber = $"^(?!{Regex.Escape(policyOne)}){Regex.Escape(policyTwo)}{Regex.Escape(policyTwo)}$",
So while I have also tried ?!.* , I still cannot get it to recognize that the policyOne is NOT allowed to be "C"
All 3 of the variables are joined together in a sql linq where clause
I can provide more details if needed.
This is my code
string AnyStart = "XXXDEFGHI";
string AnythingMiddle = "ABCXXXGHI";
string AnyEnds = "ABCDEFZZZ";
List<string> Strings = new List<string>()
{
AnythingMiddle,
AnyStart,
AnyEnds
};
string hcdpPlnCvgCD = "ABC";
string HcdpPmtFctrCd = "DEF";
string hccCpmtFctrCd = "GHI";
var patterns = new string[]{
$"^(?!{Regex.Escape(hcdpPlnCvgCD)}){Regex.Escape(HcdpPmtFctrCd)}{Regex.Escape(hccCpmtFctrCd)}$",
$"^{Regex.Escape(hcdpPlnCvgCD)}(?!.*{Regex.Escape(HcdpPmtFctrCd)}){Regex.Escape(hccCpmtFctrCd)}$",
$"^{Regex.Escape(hcdpPlnCvgCD)}{Regex.Escape(HcdpPmtFctrCd)}(?!.*{Regex.Escape(hccCpmtFctrCd)})$",
};
var wildcards = new List<string>();
foreach (var pattern in patterns)
{
var matchResult = Strings.Where(s => Regex.IsMatch(s, pattern)).ToList();
matchResult.Dump();
}
wildcards.Dump();
I'm going to suggest a few things, first you should be evaluating the 3 different patterns individually. Second it seems like a plan has some logic behind it so I propose a Plan class. Then you can use Linq to find the plans you want.
public class Plan
{
public Plan(string planCode)
{
PlanCode = planCode;
Evaluate();
}
private const string _planCoverage= "^ABC";
private const string _planPaymentFactor= "DEF";
private const string _planCoPaymentFactor = "GHI$";
public string PlanCode { get; set; }
public bool IsCoverage { get; set; }
public bool IsPayment { get; set; }
public bool IsCoPay { get; set; }
private void Evaluate()
{
IsCoverage = Regex.IsMatch(PlanCode, _planCoverage);
IsPayment = Regex.IsMatch(PlanCode, _planPaymentFactor);
IsCoPay = Regex.IsMatch(PlanCode, _planCoPaymentFactor);
}
}
using this class the following code should accomplish what you're trying to do
string anyStart = "XXXDEFGHI";
string anyMiddle = "ABCXXXGHI";
string anyEnd = "ABCDEFZZZ";
List<Plan> plans = new List<Plan>(){
new Plan(anyStart),
new Plan(anyMiddle),
new Plan(anyEnd)
};
//what your first regex tried to accomplish
List<string> noCoveragePlans = plans
.Where(plan => !plan.IsCoverage && plan.IsPayment && plan.IsCoPay)
.Select(plan => plan.PlanCode)
.ToList();
//what your second regex tried to accomplish
List<string> noPaymentPlans = plans
.Where(plan => plan.IsCoverage && !plan.IsPayment && plan.IsCoPay)
.Select(plan => plan.PlanCode)
.ToList();
//what your third regex tried to accomplish
List<string> noCoPayPlans = plans
.Where(plan => plan.IsCoverage && plan.IsPayment && !plan.IsCoPay)
.Select(plan => plan.PlanCode)
.ToList();

Linq, how to group data by ID and merge data within that ID

From the database I get the following values
PlanningID = GetValue<int>(dataReader["PlanningID"]),
PlanningStatus = GetValue<string>(dataReader["PlanningStatus"]),
Private = GetValue<int>(dataReader["Private"])
Social = GetValue<int>(dataReader["Social"])
PlanningID, PlanningStatus, Private
1, good, 10
1, fair, 5
1, bad, 1
I want to group these by planningID so that it looks like this
public class ClassResult
{
public int planningID { get; set; }
public List<PlanningStatus> PlanningStatus { get; set; }
}
public class PlanningStatus
{
public string PlanningStatus { get; set; }
public int Private { get; set; }
public int Social{ get; set; }
}
I tried this but the output was wrong:
IEnumerable<ClassResult> classResult =
from result in results
group result by new
{
result.PlanningID,
result.PlanningStatus
} into grouping
select new ClassResult
{
PlanningID = grouping.Key.PlanningID,
PlanningStatus = grouping.Key.PlanningStatus,
Private = grouping.First().Private,
Social = grouping.First().Social
};
return lrrResults;
To be honest I got no idea how to do this
Updated projection as advised below but still have multiple planning id's of lets say 1
var results =
from result in results
group result by result.PlanningID
into grouping
select new ClassResult
{
PlanningID = grouping.Key,
PlanningStatusType = grouping.Select(item => new PlanningStatusType
{
PlanningStatus = item.PlanningStatus,
Private = item.Private,
Social = item.Social,
}).ToList(),
LatestChange = grouping.First().LatestChange,
WeeklyChangeType = grouping.First().WeeklyChangeType,
Address = grouping.First().Address
};
In your query above you are grouping by both the PlanningID and PlanningStatus so the groups will contain 1 item each. What you want to do is as following:
Instantiate a new ClassResult as you did but setting the planningID but the .Key (which is now just a single property
Project each item of the grouping to a new object of type PlanningStatus using the .Select()
Code:
var classResult = from result in results
group result by result.PlanningID into grouping
select new ClassResult
{
PlanningID = grouping.Key,
PlanningStatus = grouping.Select(item => new PlanningStatus {
PlanningStatus = item.PlanningStatus,
Private = item.Private,
Social = item.Social
}).ToList()
};
Tested on some sample code and works:

Comparing two lists "List<Category>" where Category is my class

I have to find out the difference between two lists of class Category.
My Category class has these properties:
public class Category
{
public int Id { get; set; }
public string Title { get; set; }
public bool IsQuantitative
{
get { return Products.Any(x => x.IsMultiPart); }
}
public List<Product> Products { get; set; }
public string Image { get; set; }
public string Description { get; set; }
}
Try this
var firstNotSecond = list1.Except(list2).ToList();
var secondNotFirst = list2.Except(list1).ToList();
link
I would sort the two lists by Id first.
Then run through it and compare the Objects.
This is a good Object Comparer:
https://www.nuget.org/packages/CompareNETObjects/
Here a little example:
//Here you set the config like you want to have it compared
ComparisonConfig comparisonConfig = new ComparisonConfig()
{
CompareChildren = true,
CompareFields = true,
CompareReadOnly = true,
CompareProperties = true,
MaxDifferences = 1,
MaxByteArrayDifferences = 1
};
CompareLogic comparer = new CompareLogic() { Config = comparisonConfig };
list1 = list1.OrderBy(x => x.Id).ToList();
list2 = list2.OrderBy(x => x.Id).ToList();
for (int i =0;i> list1.count;i++)
{
//Here you get a bool if the two Objects are Equal
bool areEqual = comparer.Compare(list1[i], list2[i]).AreEqual;
//Here you get a List of Differences Objects. It contains Values like "expected and "actual" etc.
var differences = comparer.Compare(list1[i], list2[i]).Differences;
//Here you handle Differences etc.
}

Converting an array to object

I have 2 types of string: Mer and Spl
// Example
string testMer = "321|READY|MER";
string testSpl = "321|READY|SPL";
Then I will split them:
var splitMer = testMer.Split('|');
var splitSpl = testSpl.Split('|');
I have an object to save them
public class TestObject
{
public int id { get; set; }
public string status { get; set; }
public string type { get; set; }
}
Question: How to convert the Array into the TestObject?
var converted = new TestObject
{
id = int.Parse(splitMer[0]),
status = splitMer[1],
type = splitMer[2]
};
You will need to add some error checking.
var values = new List<string> { "321|READY|MER", "321|READY|SPL" };
var result = values.Select(x =>
{
var parts = x.Split(new [] {'|' },StringSplitOptions.RemoveEmptyEntries);
return new TestObject
{
id = Convert.ToInt32(parts[0]),
status = parts[1],
type = parts[2]
};
}).ToArray();
You just need to use object initializers and set your properties.By the way instead of storing each value into seperate variables, use a List.Then you can get your result with LINQ easily.
var splitMer = testMer.Split('|');
var testObj = new TestObject();
testObj.Id = Int32.Parse(splitMer[0]);
testObj.Status = splitMer[1];
testObj.type = splitMer[2];
How about adding a Constructor to your Class that takes a String as a Parameter. Something like this.
public class TestObject
{
public int id { get; set; }
public string status { get; set; }
public string type { get; set; }
public TestObject(string value)
{
var valueSplit = value.Split('|');
id = int.Parse(valueSplit[0]);
status = valueSplit[1];
type = valueSplit[2];
}
}
Usage:
TestObject tst1 = new TestObject(testMer);
TestObject tst2 = new TestObject(testSpl);

Categories

Resources