Accessing Distinct values of List within List for ListView - c#

I have a List "RootObject" that contains another list "Components". So basically each RootObject could have many Components. I need to get all Distinct values out of "Components" to bind to a ListView.
public class RootObject
{
public string id { get; set; }
public List<string> Components { get; set; }
public string name { get; set; }
}
I think I may need to use SelectMany but not sure how to get them...
For example I have my root object into
mylist = deserial.Deserialize<List<RootObject>>(response);
This works. I then need to get a list of Components into a ListView
`ListView.DataSource = //get list of Components`

This gets the distinct components into a list:
var distinctComponents = rootObjects
.SelectMany(r => r.Components)
.Distinct()
.OrderBy(c => c)
.ToList();
I don't know which GUI technology you are using, but a winforms ListView has no simple binding mechanism. You need to add items and subitems manually. So, you could also drop the ToList() and enumerate the query directly in a foreach-statement.

for distinct components, you'll need something like this:
List<RootObject> values = new List<RootObject>(); // assuming this is the collection
var distinctComponents = values.SelectMany(r => r.Components).Distinct().ToList();

Related

Order sublist by creation date [duplicate]

I have the following basic classes (cut down for this question):
public class Parent
{
public string Name { get; set; }
public IList<Child> Children { get; set; }
}
public class Child
{
public string Name { get; set; }
}
If I have a Parent collection, what I'd like to do is get an IList that is sorted by Parent.Name and also the Children for each parent need to be sorted by their Name.
I've tried this (which only sorts the Parents, not the Children):
IList<Parent> parents = ... //Populated
parents.OrderBy(p => p.Name).ThenBy(p => p.Children.OrderBy(c => c.Name)).ToList()
I've searched but can't find anything (probably me being dumb).
Any suggestions for a Linq newbie?
Thanks in advance
Andy
First of all, calling OrderBy on the list, the way you do, won't sort it in-place. It will return a new sorted IEnumerable; you can use .ToList() on that to turn it into a list, but it will still be a copy. Now on to the sorting itself. You really need to not just order the items in the collection, but make a copy of each item which would have its Children sorted as well. So:
IList<Parent> parents = ... //Populated
parents = (from p in parents
orderby p.Name
select new Parent
{
Name = p.Name,
Children = p.Children.OrderBy(c => c.Name).ToList()
}
).ToList();
Same solution, using LINQ method syntax:
IList<MyType> myTypeList = ... //Populated
var sortedList = myTypeList.Select(t =>
{
t.Children = t.Children.OrderBy(c => c.Name).ToList();
return t;
}).ToList();

Convert List to List<string>

I have the following problem:
public class AwesomeClass
{
public string SomethingCool { get; set; }
public string SomethingUseless { get; set; }
}
I have a class which contains a number of properties, and I need to convert a list of these classes into a list of strings, where the string represents a property in the class.
List<AwesomeClass> stuff = new List<AwesomeClass>();
//Fill the stuff list with some tings.
List<string> theCoolStuff = //Get only the SomethingCool property in the AwesomeClass list.
The reason why I need to convert this to a list of strings is because I have a method which takes a List as a parameter, but the SomethingCool property contains the data that I need for this list.
Note: I could use a foreach loop on the list and populate the List of strings but I'm looking for a more elegant method, perhaps LINQ can do this for me?
You can simply use Select:
var theCoolStuff = stuff.Select(x => x.SomethingCool).ToList();
What Select does is a projection, it projects each item and transforms (not convert) them into another form.
Note that you can even:
List<string> theCoolStuff = stuff.ConvertAll(x => x.SomethingCool);
because the List<T> has a special "conversion" method :-)
foreach (AwesomeClass member in stuff)
{
theCoolStuff.Add(member. SomethingCool)
}

LINQ Update or Insert objects into List

Ok, so I have a List that contains a collection of message objects. An updated list of message objects comes in every 60 seconds. Some of the objects in the first collection will have updated data based on an ID property inside each object.
public class Message
{
public Int64 Id { get; set; }
public string Property1 { get; set; }
public DateTime MessageDate { get; set; }
}
How in LINQ can I Insert in the updated object based on the Id?
You need to get a reference to the object Message.
Something like this:
this.Messages.ForEach(mess => {
if(mess.Id == someValue){
// do something here
}
})
List<Message> LocalList;
List<Message> ArrivingList;
var mergedItems = LocalList.Contcat(ArrivingList);
mergedItems = (from msg in mergedItems
group msg by msg.Id into grp
let sameKey = mergedItems.Where(obj => obj.Id == grp.Id)
select sameKey.Where(obj => obj.MessageDate == grp.Max(obj2 => obj2.MessageDate)).Single()).ToList();
LocalList = (List<Message>)mergedItems;
I think something similar to the above would probably "work" but I would just use a standard Dictionary /List and write a small updating routine. Just because you CAN do something with a particular tool does not mean you SHOULD.
For me LINQ based stuff can be MUCH harder to troubleshoot, understand, debug, trace, evaluate, etc.
(Replace LocalList and ArrivingList in the above example with whatever your actual variable are)

Linq extracting objects

I have a JSON "multi-level" response that I need to deserialize and from the deserialized classes structure I need to extract all the objects of a certain class.
Below the code I'm using, at the end I find that my result is empty, not populated.
// given these two classes:
[DataContract]
public class ThingsList
{
[DataMember(Name = "status")]
public string Status { get; set; }
[DataMember(Name = "since")]
public double Since { get; set; }
[DataMember(Name = "list")]
public Dictionary<string, ThingsListItem> Items { get; set; }
public DateTime SinceDate { get { return UnixTime.ToDateTime(Since); } }
}
[DataContract]
public class ThingsListItem
{
[DataMember(Name = "url")]
public string Url { get; set; }
[DataMember(Name = "title")]
public string Title { get; set; }
}
// I can deserialize my json to this structure with:
ThingsList results = JsonConvert.DeserializeObject<ThingsList>(e.Result);
// now I need to "extract" only the ThingsListItem objects, and I'm trying this:
var theList = from item in results.Items.OfType<ThingsListItem>()
select new
{
Title = item.Title,
Url = item.Url
};
// but "theList" is not populated.
The points here are (I believe):
- I try to use results.Items.OfType() in order to extract only the ThingsListItem objects, that in the "upper" class are declared in the
public Dictionary Items { get; set; }
row.
Any idea? Tell if it's not clear...
Thanks
Andrea
EDIT: updated my response for clarity.
Since your Dictionary values are of type ThingsListItem you can access them directly by using the Dictionary's Values property. There is no need to use OfType to check their type and extract them. Simply use:
var items = results.Items.Values;
The Values property would return an ICollection<ThingsListItem>. You can then iterate over the results with a foreach. LINQ does not have to be used.
While the Values property described above should be sufficient, I will point out a few issues with your original LINQ query attempt.
1) The following query is probably what you were after. Again, the Dictionary's Values property is key (no pun intended) to accessing the items:
var theList = from item in results.Items.Values
select new
{
Title = item.Title,
Url = item.Url
};
2) Why are you using new? That will return an IEnumerable of anonymous types. You already have a defined class, so why project into a new anonymous type? You should retain the underlying ThingsListItem items by selecting the item directly to get an IEnumerable<ThingsListItem>:
var theList = from item in results.Items.Values
select item;
foreach (var item in theList)
{
Console.WriteLine("Title: {0}, Url: {1}", item.Title, item.Url);
}
You would usually project into a new anonymous type to define a type with data properties you are interested in. Generally you would use them immediately after the query, whereas a selection into an existing class could be used immediately or passed around to other methods that are expecting that type.
Hopefully this has cleared up some questions for you and you have a better idea of using LINQ and when to use the new keyword. To reiterate, for your purposes it seems the Values property should suffice. Using LINQ to select the item is redundant when there are other immediate means to do so.

How to sort on the Value of an member of a List<> within a parent List<>

I have a List sort question. I am using c# 3.0 and a generic List structure like this:
public class myObject
{
public int ID { get; set; }
public List<mySetting> setting { get; set; }
}
public class mySetting
{
public int ID { get; set; }
public string Name { get; set; }
public string Value { get; set; } // sort on this!
}
with this structure, I am filling a List of myObject with a LINQ query.
List<myObject> lmo = new List<myObject>();
lmo.SomeFillOperation():
What I want to do now is sort the entire List<myObject> on the individual <mySetting>[].Value values. EDIT: ( So this would be sorting on one keyed index of , for example mySetting[3].Value). I realize I could possibly do it in my SomeFillOperation(), but I want to do it after the List is formed.
Is there a recommended or easy way to do this? Is there a good example you have seen? Thanks in advance!
Well, List<T> already has a Sort method if you want to sort it in place - or you could use LINQ's OrderBy method. OrderBy is slightly easier than Sort:
var sorted = lmo.OrderBy(x => x.Value);
but even Sort isn't too bad:
lmo.Sort((x, y) => x.Value.CompareTo(y.Value));
EDIT: Having read the comment to the question, I no longer understand the question! Leaving this answer here as a potentially useful placeholder while I have dinner...
int MyObjectComparison(MyObject x, MyObject y)
{
return x.setting[0].Value.CompareTo(y.setting[0].Value);
}
lmo.Sort(MyObjectComparison);
Of course, this assumes that you want to use the Value of the first element in setting (and that setting is guarunteed to have at least one element). Solution with less assumption will be forthcoming when more info is given.
Since you are using 3.0, use LINQ:
var newList = lmo.OrderBy(i => i.Value);
and
var newList = lmo.OrderByDescending(i => i.Value);

Categories