I am using Linq to get only unique member of a select List item. How do I return a this list...
What I have now is
var queryResult = PatientList.Select(c => c).Distinct();
PatientList = (List<SelectListItem>)queryResult;
I am getting a cast error on the second line. What should an enterprising young developer do?
Try
PatientList = queryResult.ToList();
You version uses casting, which is impossible in this case, as the query result is not a list. ToList constructs a new list, basing on the enumerable against which it is called. It does something like this:
public static List<T> ToList<T>(this IEnumerable<T> collection)
{
return new List<T>(collection);
}
You must be sure, obviously, that PatientList elements are of type SelectListItem and be aware that Distinct() will return the different OBJECTS, but not items with different fields. I.e., if in PatientList you have two independently constructed items with equal Selected, Text and Value properties, you will still have two as a result of the Distinct() call.
Additionally, what is the reason to use Select(c => c)? It effectively does noting.
I don’t know what type are the item in your list but for what you have posted you can call Distinct() directly on the list
List<int> ages = new List<int> { 21, 46, 46, 55, 17, 21, 55, 55 };
IEnumerable<int> distinctAges = ages.Distinct();
Adding .ToList() if you need to convert it to a List
Related
I have a list of strings, when I click a button I want to generate a new list with a specific number of items from my original list of strings.
I'm able to generate a random list with no repeating items but the number of items that returns is random. For example I want a new list of 5 items, sometimes it returns with 2 items other times 4 etc.
var randomList = new List.generate(
5, (_) => originalList[Random().nextInt(originalList.length)]).toSet().toList();
I've found lots of info for returning 1 random item, but nothing about multiples.
EDIT:
Thank you everyone for the responses, I was able to fix my problem by using shuffle like so
var randomList = (originalList..shuffle()).take(5).toList();
Your method of getting random items out of the original list will result in duplicates, which are then eliminated when you call .toSet(), which is why you get lists of varying lengths.
Instead of calling .toSet() to prevent duplicates, we need to be sure that no duplicates are chosen in the first place.
One way of doing that would be to generate a list of numbers from 0 up to originalList.length - 1, then shuffle them, and then choose the first n numbers from that list, and map them to values from original list.
void main() {
List<String> originalList = ["hello", "what", "goodbye", "Test", "Apple", "Banana"];
List<int> indices = List<int>.generate(originalList.length, (i) => i);
indices.shuffle();
int newCount = 3;
List<String> randomList = indices.take(newCount).map((i) => originalList[i]).toList();
print(randomList);
}
This method is efficient, and has a worst case performance of O(n), assuming dart has an efficient shuffle() implementation (which I'm sure it does).
The problem here is the list generates duplicates nonetheless.
var randomList = new List.generate(5, (_) => originalList[Random().nextInt(originalList.length)])
The list could contain [dello, kello, hello, gello, hello]
(for example, assume items are taken from the original list)
Now performing .toSet() on this will remove the duplicate hello from the list, this is what causes the list size to be random. In this instance it's two duplicates, but later on it could have more.
A simple solution for this would be
var randomList = [];
List.generate(5, (_) {
var randomString = originalList[Random().nextInt(originalList.length)];
while (randomList.contains(randomString)) {
randomString = originalList[Random().nextInt(originalList.length)];
}
randomList.add(randomString);
});
We're trying to use IN operator on BQL to select multiple inventories, but it's not working.
For example,
int[] items = new int[] { 154, 184 };
foreach (SOLine item in PXSelect<SOLine,Where<SOLine.inventoryID,In<Required<SOLine.inventoryID>>>>.Select(this, items))
{
}
I've also referred the blog below that illustrates using the IN operator for a string:
https://asiablog.acumatica.com/2017/11/sql-in-operator-in-bql.html. We are trying for integer type in a similar way. I'm not sure what we're missing. It would be great if some one can help identify.
Acumatica ORM entity DB types are all nullable. You are using an array of non-nullable values 'int[]' instead of an array of nullable values 'int?[]'.
Code:
int?[] items = new int?[] { 154, 184 };
foreach (SOLine item in PXSelect<SOLine,
Where<SOLine.inventoryID,
In<Required<SOLine.inventoryID>>>>.Select(this, items))
{
}
I'm trying to select objects from the database with Entity Framework into an anonymous type. When using Union and Selecting a Subcollection, I get an exception:
System.ArgumentException: The 'Distinct' operation cannot be applied to the collection ResultType of the specified argument.
My model contains several types derived from BaseType. This base type has a reference to RefType which contains a collection of ItemType. The types derived from BaseType are stored in separate tables, thus the Union.
The query looks like this:
var q1 = ctx.Set<Type1>().Select(x => new { x.Id, x.Ref.Items });
var q2 = ctx.Set<Type2>().Select(x => new { x.Id, x.Ref.Items });
q1.Union(q2).ToList();
But to reproduce the error, you can even union queries of the same type, as long as you select a collection.
I would do the select after the union, but to union Type1, Type2, etc. I must cast them to BaseType, which is not allowed in LINQ-to-SQL.
Any way to do this in the same query?
The exception emerges from Entity Framework's query generation pipeline when the ExpressionConverter tries to translate the expression q1.Union(q2) into SQL.
In a valid query you'll see that EF adds a DISTINCT clause to the SQL query. A type with collection properties (x.Ref.Items) doesn't pass as a valid argument for a Distinct operation and EF throws the exception you see.
Unfortunately, using Concat instead of Union is not a valid work-around. EF will also throw an exception:
The nested query is not supported. Operation1='UnionAll' Operation2='MultiStreamNest'
Which means that it's simply not supported to concat nested queries containing types with collection properties.
So you have to do the Union in memory:
var result = q1.AsEnumerable() // Continues the query in memory
.Union(q2).ToList();
C# doesn't have any problem with equating anonymous types containing collections: it simply considers any collection member as unequal to another collections member. This does mean that the query can produce a collection containing non-unique results (same Id, same Items) which may not be expected when relying on Union's implicit Distinct.
I am not sure why, for some reason distinct is failing, maybe because it is anonymous type, and it is still IQuerable, I would suggest firing the query something like this
var q1 = ctx.Set<Type1>().Select(x => new { x.Id, x.Ref.Items }).ToList<object>();
var q2 = ctx.Set<Type2>().Select(x => new { x.Id, x.Ref.Items }).ToList<object>();
q1.Union(q2).ToList();
Note that in this case, Distinct will check for all properties equality, meaning if 2 objects have the same id but different items, both will be there.
if you don't care about distinct values, you can also use concat
if you care about distinct and first option didn't work, you can use group by and implement your own distinct,
something like this
var q1 = ctx.Set<Type1>().Select(x => new { Id = x.Id, Items =x.Ref.Items });
var q2 = ctx.Set<Type2>().Select(x => new { Id = x.Id, Items = x.Ref.Items });
//this will group by id, and select the first object items
var qFinal = q1.concat(q2).GroupBy(e => e.id)
.select(e => new {e.key, e.First().Items})
.ToList();
maybe you don't want First(), you can use whatever you want
I am using Entity Framework 7 Code First
I have a function that needs to returns a list of Countries(ids,Names) linked to a User.
The User isn't directly linked to the Country but is linked via the City. City is linked to State. State is linked to Country.
I decided to use a GroupBy to get the list of countries.
public async Task<IEnumerable<Country>> Search(int userId)
{
var table = await _db.Cities
.Include(ci => ci.States.Country)
.Select(ci => ci.States.Country)
.OrderBy(co => co.CountryName)
.GroupBy(co=>co.pk_CountryId)
.ToListAsync()
;
return table;
}
However I get the error:
CS0266 Cannot implicitly convert type
'System.Collections.Generic.List <System.Linq.IGrouping> to
'System.Collections.Generic.List'
How do I return a variable IEnumerable<Country> as that is what the receiving code expects i.e. a list of Countries?
Am I doing my grouping correct?
For performance I assume grouping is better than a distinct or a contains
If you want to have the distinct countries, you can use a select afterwards to select the first country in each IGrouping<int,Country>:
public async Task<IEnumerable<Country>> Search(int userId)
{
return await _db.Cities
.Include(ci => ci.States.Country)
.Select(ci => ci.States.Country)
.OrderBy(co => co.CountryName)
.GroupBy(co=>co.pk_CountryId)
.Select(co => co.FirstOrDefault())
.ToListAsync();
}
Also a little sidenote, the Include isn't necessary here, eager loading the countries would only be useful if you were to return the States and wanted its Country property be populated. The Select makes sure you're grabbing the Country, you're not even fetching the states anymore from database.
Lets say I have the following JPQL query
SELECT e.column1, e.column2, SUM(e.column3), SUM(e.column4) FROM Entity e GROUP BY e.column1, e.column2
Obviously I wont be returning an Entity object but something a bit more complex. How do I return this in the method?
public List<???> query1() {
Query q = entityManager.createQuery("...");
List<Something???> list = q.getResultList();
return list;
}
Such a query returns a List<Object[]>, where each element is thus an array of Objects. The first element of the array will have the type of Entity.column1, the second one will have the type of Entity.column2, and the last 2 ones will be (with Hibernate at least) of type Long (check with EclipseLink).
It's up to you to transform the List<Object[]> in a List<Foo>, by simply looping over the list of objects and transforming each one into a Foo. You may also use the constructor notation directly in the query (provided Foo has such a constructor), but I personally dislike it, because it isn't refactorable:
select new com.baz.bar.Foo(e.column1, e.column2, SUM(e.column3), SUM(e.column4)) from ...