MyObject()
{
String dept;
List<int> id;
Object obj;
}
Using LINQ, how can I return a list of the above objects organized as follows:
Group all of the obj objects by [ department and EQUAL id list ]. The list being considered equal if it contains the same numbers, not necessarily the same order(a set).
GroupBy has an overload that accepts a custom IEqualityComparer<MyObject>. Write one that regards two objects as equal when dept is equal and id is set-equal, and pass it as an argument.
A convenient way to implement set equality is to write
new HashSet(x.id).SetEquals(new HashSet(y.id))
although this will end up being inefficient and probably not the best idea if there are lots of comparisons to make.
Building off of Jon's answer, if efficiency is an issue, you can store the HashSet for each object in an anonymous object:
myObjects.Select(x => new { myObject = x, hashSet = new HashSet(x.id) })
.GroupBy(x => x.hashSet, HashSet<int>.CreateSetComparer())
.SelectMany(x => x.GroupBy(y => y.myObject.dept))
If you want to perform only one GroupBy you could store the HashSet in a Tuple or custom class, but then you would have to create your own IEqualityComparer.
Related
I have a HashSet of ID numbers, stored as integers:
HashSet<int> IDList; // Assume that this is created with a new statement in the constructor.
I have a SortedList of objects, indexed by the integers found in the HashSet:
SortedList<int,myClass> masterListOfMyClass;
I want to use the HashSet to create a List as a subset of the masterListOfMyclass.
After wasting all day trying to figure out the Linq query, I eventually gave up and wrote the following, which works:
public List<myclass> SubSet {
get {
List<myClass> xList = new List<myClass>();
foreach (int x in IDList) {
if (masterListOfMyClass.ContainsKey(x)) {
xList.Add(masterListOfMyClass[x]);
}
}
return xList;
}
private set { }
}
So, I have two questions here:
What is the appropriate Linq query? I'm finding Linq extremely frustrating to try to figuere out. Just when I think I've got it, it turns around and "goes on strike".
Is a Linq query any better -- or worse -- than what I have written here?
var xList = IDList
.Where(masterListOfMyClass.ContainsKey)
.Select(x => masterListOfMyClass[x])
.ToList();
If your lists both have equally large numbers of items, you may wish to consider inverting the query (i.e. iterate through masterListOfMyClass and query IDList) since a HashSet is faster for random queries.
Edit:
It's less neat, but you could save a lookup into masterListOfMyClass with the following query, which would be a bit faster:
var xList = IDList
.Select(x => { myClass y; masterListOfMyClass.TryGetValue(x, out y); return y; })
.Where(x => x != null)
.ToList();
foreach (int x in IDList.Where(x => masterListOfMyClass.ContainsKey(x)))
{
xList.Add(masterListOfMyClass[x]);
}
This is the appropriate linq query for your loop.
Here the linq query will not effective in my point of view..
Here is the Linq expression:
List<myClass> xList = masterListOfMyClass
.Where(x => IDList.Contains(x.Key))
.Select(x => x.Value).ToList();
There is no big difference in the performance in such a small example, Linq is slower in general, it actually uses iterations under the hood too. The thing you get with ling is, imho, clearer code and the execution is defered until it is needed. Not i my example though, when I call .ToList().
Another option would be (which is intentionally the same as Sankarann's first answer)
return (
from x in IDList
where masterListOfMyClass.ContainsKey(x)
select masterListOfMyClass[x]
).ToList();
However, are you sure you want a List to be returned? Usually, when working with IEnumerable<> you should chain your calls using IEnumerable<> until the point where you actually need the data. There you can decide to e.g. loop once (use the iterator) or actually pull the data in some sort of cache using the ToList(), ToArray() etc. methods.
Also, exposing a List<> to the public implies that modifying this list has an impact on the calling class. I would leave it to the user of the property to decide to make a local copy or continue using the IEnumerable<>.
Second, as your private setter is empty, setting the 'SubSet' has no impact on the functionality. This again is confusing and I would avoid it.
An alternate (an maybe less confusing) declaration of your property might look like this
public IEnumerable<myclass> SubSet {
get {
return from x in IDList
where masterListOfMyClass.ContainsKey(x)
select masterListOfMyClass[x]
}
}
In C#, I have an object type 'A' that contains a list of key value pairs.
The key value pairs is a category string and a value string.
To instantiate object type A, I would have to do the following:
List<KeyValuePair> keyValuePairs = new List<KeyValuePair>();
keyValuePairs.Add(new KeyValuePair<"Country", "U.S.A">());
keyValuePairs.Add(new KeyValuePair<"Name", "Mo">());
keyValuePairs.Add(new KeyValuePair<"Age", "33">());
A a = new A(keyValuePairs);
Eventually, I will have a List of A object types and I want to manipulate the list so that i only get unique values and I base it only on the country name. Therefore, I want the list to be reduced to only have ONE "Country", "U.S.A", even if it appears more than once.
I was looking into the linq Distinct, but it does not do what I want because it I can't define any parameters and because it doesn't seem to be able to catch two equivalent objects of type A. I know that I can override the "Equals" method, but it still doesn't solve the my problem, which is to render the list distinct based on ONE of the key value pairs.
To expand upon Karl Anderson's suggestion of using morelinq, if you're unable to (or don't want to) link to another dll for your project, I implemented this myself awhile ago:
public static IEnumerable<T> DistinctBy<T, U>(this IEnumerable<T> source, Func<T, U>selector)
{
var contained = new Dictionary<U, bool>();
foreach (var elem in source)
{
U selected = selector(elem);
bool has;
if (!contained.TryGetValue(selected, out has))
{
contained[selected] = true;
yield return elem;
}
}
}
Used as follows:
collection.DistinctBy(elem => elem.Property);
In versions of .NET that support it, you can use a HashSet<T> instead of a Dictionary<T, Bool>, since we don't really care what the value is so much as that it has already been hashed.
Check out the DistinctBy syntax in the morelinq project.
A a = new A(keyValuePairs);
a = a.DistinctBy(k => new { k.Key, k.Value }).ToList();
You need to select the distinct property first:
Because it's a list inside a list, you can use the SelectMany. The SelectMany will concat the results of subselections.
List<A> listOfA = new List<A>();
listOfA.SelectMany(a => a.KeyValuePairs
.Where(keyValue => keyValue.Key == "Country")
.Select(keyValue => keyValue.Value))
.Distinct();
This should be it. It will select all values where the key is "Country" and concat the lists. Final it will distinct the country's. Given that the property KeyValuePairs of the class A is at least a IEnumerable< KeyValuePair< string, string>>
var result = keyValuePairs.GroupBy(x => x.Key)
.SelectMany(g => g.Key == "Country" ? g.Distinct() : g);
You can use the groupby statement. From here you can do all kind off cool stuf
listOfA.GroupBy(i=>i.Value)
You can groupby the value and then sum all the keys or something other usefull
I have a method that given 2 strings he returns a number (between 0 and 100) which represents is how alike they are, being 0 "not similar at all" and 100 "they are the same"
Now the thing is that i have a list of County (string name, GeoRef coordinates, string Mayor) which i would like to sort based on the return of my function...
im looking for something like myList.Sort(f=>MyScoreEvaluator("York",f.Name))
Can anyone tell me how to do so?
Edit1: I dont think that the method "Sort" is quite i want... Sort compare itens inside of the list... i want to compare the itens of the list against a external info and based on that result sort the items
The OrderBy and OrderByDescending are returning the same item order...
Edit2: Heres is the code of the OrderBy I'm using: aux.OrderBy(f => StringComparisonHelper.HowAlike(f.Name, countyNameSearched));
You can use OrderBy, and re-assign your list:
list = list.OrderBy(f => MyScoreEvaluator("York", f.Name))
You could just use OrderBy:
list.OrderBy(f => MyScoreEvaluator("York", f.Name))
Or Implement a custom Comparer:
public static int SortByName(County x, County y)
{
return x.Name.CompareTo(y.Name);
}
Usage:
list.Sort(new Comparison<County>(SortByName))
There is an OrderBy in LINQ:
var sorted = myList.OrderBy(f => MyScoreEvaluator("York", f.Name))
Or to sort descendingly:
var sortedDesc = myList.OrderByDescending(f => MyScoreEvaluator("York", f.Name))
It's very easy to use the LINQ OrderBy extension (see others' answers).
If you want to use Sort, it would be:
myList.Sort((x, y) => MyScoreEvaluator("York", x.Name)
.CompareTo(MyScoreEvaluator("York", y.Name)));
This assumes that myList is a System.Collections.Generic.List<>.
If you want the other sort direction, swap x and y on one side of the lambda arrow =>, of course.
EDIT:
Remember .Sort method on List<> modifies the same instance. The return type of Sort method is void. On the other hand, OrderBy creates a new IEnumerable<> on which you can call .ToList() to get a new list object. The old object is unchanged. You might assign the new object to the variable that held the original list. Other variables that reference the old object won't be affected by that. Example:
myList = myList.OrderBy(f => MyScoreEvaluator("York", f.Name)).ToList();
NEW EDIT:
If performance is an issue, it's not clear which of these two to use. The OrderBy method calls the MyScoreEvaluator only once per item in your original list. The Sort method as presented here, calls MyScoreEvaluator a lot more times, because it doesn't "remember" the result of each MyScoreEvaluator call (the Comparison<> delegate instance is a black box to the Sort algorithm). So if it wants to compare "Fork" and "Kork", it calls MyScoreEvaluator twice. Then afterwards if it wants to compare "Kork" and "Yorc", it does the "Kork" MyScoreEvaluator again. On the other hand, the sort algorithm of List<>.Sort is superior to that of OrderBy.
So I have this C# list:
List<DatsWussup.Models.JQGridMessage> gridMessages = new List<DatsWussup.Models.JQGridMessage>();
Each JQGridMessage has a property called age. What's the quickest and most efficient way to sort this list by age (youngest first). Age is an int.
Thanks!
The List<T> class has a Sort method which can be used to in place sort the data. One overload takes a Comparison delegate that can be implemented via an anonymous function. For example
gridMessages.Sort((x, y) => x.Age.CompareTo(y.Age));
Use Linq:
var sortedEnumerable = gridMessages.OrderBy(m => m.Age);
This will return a new IEnumerable sorted by age.
gridMessages.Sort((m1, m2) => m1.Age.CompareTo(m2.Age));
Can you use:
gridMessages = gridMessages.OrderBy(x => x.age).toList();
I have a list of objects. That objects have various field, e.g. age and name
Now sometimes I'd like to sort the list by names and sometimes by age. Additional sometimes increasing order and sometimes decreasing order.
Now I understand that i should implement the Comparable interface in my object and override the CompareTo method.
But how can i do this when i want to support various sorting orders?
Do i have to set the sorting order in my object or is it somehow possible to pass the sorting order by the sort method call?
The method call can do everything; no need for a comparer:
list.Sort((x,y)=>string.Compare(x.Name,y.Name));
list.Sort((x,y)=>y.Age.CompareTo(x.Age)); // desc
list.Sort((x,y)=>x.Age.CompareTo(y.Age)); // asc
Note the second is descending, by swapping x/y in the compare.
If you're using List<T> and you want to sort the list in place, then the Sort function provides an overload that accepts a Comparison<T>. You can use this to provide different comparisons for a list.
For example, to sort on Age:
list.Sort((x, y) => x.Age.CompareTo(y.Age));
To sort on Name:
list.Sort((x, y) => string.Compare(x.Name, y.Name));
To sort in descending order, simply reverse the parameters.
Alternatively, you could use LINQ to create various queries against your list that provide the results in whatever order you like, but this won't have any effect upon the underlying list (whether that's bad or good is up to you):
var byAge = list.OrderBy(x => x.Age);
var byName = list.OrderBy(x => x.Name);
To sort in descending order, use OrderByDescending in place of OrderBy.
You can also just use LINQ to handle this:
var sortedByAge = myList.OrderBy(i => i.Age);
var sortedByName = myList.OrderBy(i => i.Name);
If you want to handle sorting in place, you can use List<T>.Sort(Comparison<T>):
// Sort by Age
myList.Sort( (l, r) => l.Age.CompareTo(r.Age) );
// Sort by Name
myList.Sort( (l, r) => l.Name.CompareTo(r.Name) );
You can sort your objects data with linq
something like this
var query = from cust in customers
orderby cust.Age ascending
select cust;
You can also use
list.OrderByDescending(a => a.Age);
or
list.OrderByAscending(a => a.Age);