NRules—How to Build List of Array Indexes of Matches - nrules

I have two lists of objects. I want to loop though the first list and see if there are any matches in the second list, based on multiple fields, and I'd like to use a method which returns a bool to do the logic. However, I don't know if that will be possible. For the items in the first list that I'm looping through, when there is a match, I want to add the index to a list, building up a list of the indexes which match.
I know that you can look at an IEnumerable in LINQ and get back a list of indexes based on matches, but I'm not sure if that is the way to do this. For example:
myarray
.Select((p, i) => new { Item = p, Index = i })
.Where(p => SomeCondition(p.Item))
.Select(p => p.Index);
With the list of indexes that is created, I want to add those numbers to an object which will be output in the "Then()". Let me try and show this in pseudo code. In this example, let's say there are 10 objects in each of the lists, and there items 0, 2, and 7 match.
public override void Define()
{
ListOfObjects inbound; // fact in memory with 10 objects
ListOfObjects outbound; // fact in memory with 10 objects
List<int> matchingIndexes; // for storing the indexes of objects that match
OutputObject outputObject; // do store output data based on indexes
When()
.Match(() => inbound, some criteria) // get list of objects--this already works in my code
.Match(() => outbound, some other criteria) // get list of objects--this already works in my code
// Loop through inbound and for each matching item in outbound, add inbound's array index to "matchingIndexes".
// Should looping occur here or in "DoSomeLogic"? Maybe it makes sense to do all the looping and logic
// in "DoSomeLogic()" and have that return the list of indexes, but how do I assign that
// value to "matchingIndexes"?
.Match/Query/Whatever(() => matchingIndexes, DoSomeLogic(inbound, outbound))
Then()
.Do(ctx => outputObject.ProcessMatchingIndexes(matchingIndexes))
}
"matchingIndexes" should contain a list of 3 integers: 0, 2, and 7. "outputObject.ProcessMatchingIndexes" will receive that list at a parameter and do some things with those numbers.

Related

.net core when I read from appsettings, the sort is changed. Why?

I have this config in appsettings.json:
"CategoriesTypes": [ "Country", "State", "Semester" ],
in the code I read values like:
var array = Configuration.GetSection("CategoriesTypes").AsEnumerable() .Where(o => !string.IsNullOrEmpty(o.Value)).Select(o => o.Value).ToArray()
// output of foreach loop:
"Semester", "State", "Country"
Why The sort is changed?
IEnumerable do not pretend to keep items in order, unless you ask for. And as described in the docs
Methods that are used in a query that returns a sequence of values do not consume the target data until the query object is enumerated.
When you iterate through an IEnumerable it is just navigating to the previous/next item without knowing it in advance. So IEnumerable do not keep items sorted, because sorting requires to enumerate through the whole items in the list.
If you need to sort the list just use Linq extensions OrderBy or OrdrByDescending which will return IOrderedEnumerable<T>.

Filter List to the same list using Linq

How can i filter the same list using a certain condition. i know using two lists. I want to do it with the same list ..
If i have a list called lstValues Which has Name and count, i want to filter
all the items that has count as 0.
So i created another list
lstFilterdedValues.addRange(lstValues.Where(i => i.Count > 0)));
this works.. But i dont want to use another new List called lstFilteredValues.
I want something like
lstValues =lstValues.Where(i => i.Count > 0)).Select(k=>(k));
But this doesnt work.
Use ToList() call:
lstValues = lstValues.Where(i => i.Count > 0).ToList();
It will create new list and assign it back to your lstValues variable.
If you don't want to create new list and reassign the variable you can use List<T>.RemoveAll method:
lstValues.RemoveAll(i => i.Count <= 0);
As you can see, you have to reverse the condition, because it specifies which items will be removed, not which should stay in the list.

Finding items from a list in an array stored in a DB field

I have a legacy database that has data elements stored as a comma delimited list in a single database field. (I didn't design that, I'm just stuck with it.)
I have a list of strings that I would like to match to any of the individual values in the "array" in the DB field and am not sure how to do this in Linq.
My list:
List<string> items= new List<string>();
items.Add("Item1");
items.Add("Item2");
The DB field "Products" would contain data something like:
"Item1,Item3,Item4"
"Item3,Item5,Item6"
"Item2,Item7,Item6"
"Item1,Item2"
"Item1"
My first pass at the Linq query was:
var results = (from o in Order
.Where(p=> items.Contains(p.Products)
But I know that won't work. because it will only return the records that contain only "Item1" or "Item2". So with the example data above it would return 0 records. I need to have it return two records.
Any suggestions?
There is a simple clever trick for searching comma-separated lists. First, add an extra , to the beginning and end of the target value (the product list), and the search value. Then search for that exact string. So for example, you would search ,Item1,Item3,Item4, for ,Item1,. The purpose of this is to prevent false positives, i.e., Item12,Item3 finding a match for Item1, while allowing items at the beginning/end of the list to be properly found.
Then, you can use the LINQ .Any method to check that any item in your list is a match to the product list, like the following:
var results = (from o in Order
.Where(o => items.Any(i => (","+o.Products+",").Contains(","+i+",")))
One way would be to parse the list in the Products field:
var results = (from o in Order
.Where(o => items.Any(i => o.Products.Split(',').Contains(i))
But that would parse the string multiple times for each record. You could try pulling back ALL of the records, parsing each record once, then doing the comparison:
var results = from o in Order
let prods = o.Products.Split(',')
where items.Any(i => prods.Contains(i))
select o;

Imroving/Modifying LINQ query

I already have a variable containing some groups. I generated that using the following LINQ query:
var historyGroups = from payee in list
group payee by payee.Payee.Name into groups
orderby groups.Key
select new {PayeeName = groups.Key, List = groups };
Now my historyGroups variable can contain many groups. Each of those groups has a key which is a string and Results View is sorted according to that. Now inside each of those groups there is a List corresponding to the key. Inside that List there are elements and each one those element is an object of a particular type. One of it's fields is of type System.DateTime. I want to sort this internal List by date.
Can anyone help with this? May be modify the above query or a new query on variable historyGroups.
Thanks
It is not clear to me what you want to sort on (the payee type definition is missing as well)
var historyGroups = from payee in list
group payee by payee.Payee.Name into groups
orderby groups.Key
select new {
PayeeName = groups.Key,
List = groups.OrderBy(payee2 => payee2.SomeDateTimeField)
};
Is most straightforward.
If you really want to sort only by date (and not time), use SomeDateTimeField.Date.
Inside that List there are elements and each one those element is an object of a particular type. One of it's fields is of type System.DateTime
This leads me to maybe(?) suspect
List = groups.OrderBy(payee2 => payee2.ParticularTypedElement.DateTimeField)
Or perhaps even
List = groups.OrderBy(payee2 => payee2.ObjectsOfParticularType
.OfType<DateTime>()
.FirstOrDefault()
)
I hope next time you can clarfy the question a bit better, so we don't have to guess that much (and come up with a confusing answer)

Checking for duplicates in a complex object using Linq or Lambda expression

I've just started learning linq and lambda expressions, and they seem to be a good fit for finding duplicates in a complex object collection, but I'm getting a little confused and hope someone can help put me back on the path to happy coding.
My object is structured like list.list.uniqueCustomerIdentifier
I need to ensure there are no duplicate uniqueCustomerIdentifier with in the entire complex object. If there are duplicates, I need to identify which are duplicated and return a list of the duplicates.
Unpack the hierarchy
Project each element to its uniqueID property
Group these ID's up
Filter the groups by groups that have more than 1 element
Project each group to the group's key (back to uniqueID)
Enumerate the query and store the result in a list.
var result =
myList
.SelectMany(x => x.InnerList)
.Select(y => y.uniqueCustomerIdentifier)
.GroupBy(id => id)
.Where(g => g.Skip(1).Any())
.Select(g => g.Key)
.ToList()
There is a linq operator Distinct( ), that allows you to filter down to a distinct set of records if you only want the ids. If you have setup your class to override equals you or have an IEqualityComparer you can directly call the Distinct extension method to return the unique results from the list. As an added bonus you can also use the Union and Intersect methods to merge or filter between two lists.
Another option would be to group by the id and then select the first element.
var results = from item in list
group item by item.id into g
select g.First();
If you want to flatten the two list hierarchies, use the SelectMany method to flatten an IEnumerable<IEnumerable<T>> into IEnumerable<T>.

Resources