Combining Variable Numbers of Lists w/ LINQ - linq

I have a list (List) of objects.
Each of those objects contains a list (List) of strings describing them.
I'm needing to create a dropdown containing all of the distinct strings used to describe the objects (Cards). To do this, I need a list of distinct strings used.
Any idea how/if this can be done with LINQ?

You can use the SelectMany extension method/operator to flatten a collection into the individual elements.
listOfObjects.SelectMany(x => x.DescriptionStrings).Distinct()
This will select all the strings out of the collection of description strings for each object in your list of objects.

LINQ has a Distinct function.
Assuming "_cards" exists as instance variable of List and Card.Descriptions returns the descriptions and "cardsComboBox" (in WinForms):
cardsComboBox.AutoCompleteSource = _cards.SelectMany(c => c.Descriptions).Distinct();
A reminder that that will be the list of card descriptions at the time of binding however. If you want to keep it synchronised when _cards get updated then you'll have to do some more fancy footwork or look at a reactive binding source. (We use Bindable.Linq)

Related

Redux/React state normalization - why maintain a separate array of IDs?

Following the tutorial by Dan Abramov here: https://egghead.io/lessons/javascript-redux-normalizing-the-state-shape
He doesn't seem to explain the benefit of maintaining an extra reducer with an array of todo IDs (allIds), would it not be easier to have just the one byId reducer and user Object.keys or Object.values to iterate over it?
The sample Todo app shows a list of todos, in the order in which they were created. It's not possible to retrieve that ordered list in a way that is guaranteed to work across browsers using an Object and Object.keys.
JS Object properties are unordered, but arrays have an order. So the ordering of the output of Object.keys() is not guaranteed to have any relationship to the order in which the keys were added. The array allows the reducer to display the todos in the order in which they were added.
Theoretically you could use a Map, as the keys in a Map are ordered. However, there's no way to re-order the contents of a Map. With an array you could re-order the IDs without needing to touch the todo objects themselves.
In other words, the array data structure is better suited to storing ordered lists than both Object and Map.

Clean way to write this query

I'm looking for a clean way to write this Linq query.
Basically I have a collection of objects with id's, then using nhibernate and Linq, I need to check if the nhibernate entity has a subclass collection where all id's in object collection exist in the nhibernate subclass collection.
If there was just one item this would work:
var objectImCheckingAgainst = ... //irrelevant
where Obj.SubObj.Any(a => a.id == objectImCheckingAgainst.Id)
Now I want to instead somehow pass a list of objectImCheckingAgainst and return true only if the Obj.SubObj collection contains all items in list of objectImCheckingAgainst based on Id.
I like to use GroupJoin for this.
return objectImCheckingAgainst.GroupJoin(Obj.SubObj,
a => a.Id,
b => b.id,
(a, b) => b.Any())
.All(c => c);
I believe this query should be more or less self-explanatory, but essentially, this joins the two collections using their respective ids as keys, then groups those results. Then for each of those groupings, it determines whether any matches exist. Finally, it ensures that all groupings had matches.
A useful alternative that I sometimes use is .Count() == 1 instead of the .Any(). Obviously, the difference there is whether you want to support multiple elements with the same id matching. From your description, it sounded like that either doesn't matter or is enforced by another means. But that's an easy swap, either way.
An important concept in GroupJoin that I know is relevant, but may or may not be obvious, is that the first enumerable (which is to say, the first argument to the extension method, or objectImCheckingAgainst in this example) will have all its elements included in the result, but the second one may or may not. It's not like Join, where the ordering is irrelevant. If you're used to SQL, these are the elementary beginnings of a LEFT OUTER JOIN.
Another way you could accomplish this, somewhat more simply but not as efficiently, would be to simply nest the queries:
return objectImCheckingAgainst.All(c => Obj.SubObj.Any(x => x.id == c.Id));
I say this because it's pretty similar to the example you provided.
I don't have any experience with NHibernate, but I know many ORMs (I believe EF included) will map this to SQL, so efficiency may or may not be a concern. But in general, I like to write LINQ as close to par as I can so it works as well in memory as against a database, so I'd go with the first one I mentioned.
I'm not well versed in LINQ-to-NHibernate but when using LINQ against any SQL backen it's always important to keep an eye on the generated SQL. I think this where clause...
where Obj.SubObj.All(a => idList.Contains(a.id))
...will produce the best SQL (having an IN statement).
idList is a list of Ids extracted from the list of objectImCheckingAgainst objects.

dynamically select fields in linq

I have this here:
Dim query = FromTableRows.Select(Function(Row) Row.Item(_SqlSyntaxChecker.SelectedFields(0)))
Row is a normal DataRow, so I can get the field value of the rows like this: Row.Item(0), Row.Item(1), etc.
SelectedFields contains the field names of the FromTableRows.
Now, I would like to select all the fields in the SelectedFields list, while the number of the selected fields can vary.
Is this possible? How should I modify the code?
Thanks.
You can simply make use of the ItemArray property, if I understand your question correctly.
FromTableRows.Select(Function(Row) Row.ItemArray)
The ItemArray property is an object array that contains the elements found in the DataRow. You will, of course, lose any mapping via this method from columns to elements, but it sounds like that's what you want.

Concatenating a LINQ query and LINQ sort statement

I'm having a problem joining two LINQ queries.
Currently, my (original) code looks like this
s.AnimalTypes.Sort((x, y) => string.Compare(x.Type, y.Type));
What I'm needing to do is change this based on a date, then select all data past that date, so I have
s.AnimalTypes.Select(t=>t.DateChanged > dateIn).ToList()
s.AnimalTypes.Sort((…
This doesn't look right as it's not sorting the data selected, rather sorting everything in s.AnimalTypes.
Is there a way to concatenate the two LINQ lines? I've tried
s.AnimalTypes.Select(t=>t.DateChanged > dateIn).ToList().Sort((…
but this gives me an error on the Sort section.
Is there a simple way to do this? I've looked around and Grouo and OrderBy keep cropping up, but I'm not sure these are what I need here.
Thanks
From your description, I believe you want something like:
var results = s.AnimalTypes.Where(t => t.DateChanged > dateIn).OrderBy(t => t.Type);
You can call ToList() to convert to a List<T> at the end if required.
There are a couple of fundamental concepts I believe you are missing here -
First, unlike List<T>.Sort, the LINQ extension methods don't change the original collections, but rather return a new IEnumerable<T> with the filtered or sorted results. This means you always need to assign something to the return value (hence my var results = above).
Second, Select performs a mapping operation - transforming the data from one form to another. For example, you could use it to extract out the DateChanged (Select(t => t.DateChanged)), but this would give you an enumeration of dates, not the original animal types. In order to filter or restrict the list with a predicate (criteria), you'd use Where instead.
Finally, you can use OrderBy to reorder the resulting enumerable.
You are using Select when you actually want to use Where.
Select is a projection from one a collection of one type into another type - you won't increase or reduce the number of items in a collection using Select, but you can instead select each object's name or some other property.
Where is what you would use to filter a collection based on a boolean predicate.

How to filter custom columns from SharePoint list using LINQ?

My requirement is to get items, only from custom-columns, in a SharePoint list using LINQ.
Since my custom columns are created dynamically based on some calculations done on another SPList, it keeps increasing and decreasing in the count frequently, therefore I cannot use SPMetal.
I need to include a condition (!(SPBuiltInFieldId.Contains(field.Id))) to check if the items are taken only from custom fields in the following query.
List<SPListItem> AllResponses = (from SPListItem Response in oList.Items
select Response).ToList();
Please advice. Thanks!
I'm not sure it's possible to have a list item that contains only custom columns. Even if Title is not there, you'll have ID, Modified, Created, etc. Plus, there will be a number of hidden built-in columns.
If you want a list of items that contain items with custom fields, you can try something like the following, which utilizes Where and Any methods:
List<SPListItem> AllResponses =
(from SPListItem Response in oList.Items select Response)
.Where(item => item.Fields
.Cast<SPField>()
.Any(field => !SPBuiltInFieldId.Contains(field.Id)))
.ToList();
This will return all items that have at least one custom field.

Resources