c# order a List<Dictionary<string,object>> - c#

how to order a List<Dictionary<String,object>> the object contains only string
the dictionary is structured as below
[name: mario]
[surname: rossi]
[address: xxxxxx]
[age: 40]
i'd like to order the list of these dictionaries by "age"
may you help me please?
i've tried with:
myList.Select(x => x.OrderBy(y=>y.Value))
it gives me this error: the value isn't a string(ok i aggree with him, it's an object, i've to cast in some way)
but more important is that i can't tell to the "orderby" methods that it must order by age

You want something along the lines of
var sorted = myList.OrderBy(dict => Convert.ToInt32(dict["age"]));
I 've used Convert.ToInt32 defensively because there's a small chance you are using another data type for the age, and casting (unboxing) to the wrong type would throw an exception.

myList.Sort((x,y) => ((int)x["age"]).CompareTo((int)y["age"]));
or similar:
myList.Sort((x, y) => Comparer.Default.Compare(x["age"], y["age"]));
However! It would be much easier if you used a proper type instead of the dictionary; then it would just be:
myList.Sort((x,y) => x.Age.CompareTo(y.Age));

Related

Using Lookup in Linq

Need to fetch the first record from Lookup when a condition is satisfied. In below, resId will be key having one or more lists value. In vb, used the below code to fetch the record having resId and record satisfying the below condition. It works perfect.. how can I use the same logic with C#
Lookup<Guid, Class> responseLookup;
result = responseLookup(Guid).FirstOrDefault(
Function(x) catId.Equals(x.catCode)
Tried to convert but was receiving "Method name expected" error
This should work:
responseLookup[Guid].FirstOrDefault(x => catId.Equals(x.catCode))
The => is a lambda-expression. In your case a delegate that excepts a single instance from your list and returns a bool.
Assuming Guid in responseLookup(Guid) is some Guid value, not the type name, the following should work (I suggest using standard naming conventions and refrain from using BCL type names as variable names):
Guid guid = ...;
var result = responseLookup[guid]
.FirstOrDefault(x => catId.Equals(x.catCode));

How can I extract values from a list of an unknown value type?

I can't seem to figure out how to convert a orderedDictionary with values consisting of lists of childinstances and lists of tuples containing childinstances into a list of the childinstances as their parent type (Item) without calling each list type in the OrderedDictionary explicitly...
//Here is a sample of an entry in the OrderedDictionary
{ "Contextuals", new List<Contextual>{} },
//and some of the entries are lists of tuples; where the int represents an ammount value of "stacked" objects:
{"Consumables", new List<Tuple<Consumable,int>>{} },
So I have a loop that iterates through said dictionary:
(I tried using the type of object in place of UnknownListType but am not sure if that would be valid since I can't iterate through an object as a list without stating it's explicit type.)
//convertedList collects all the childinstances as their base type (Item)
List<Item> convertedList = new List<Item>();
foreach (KeyValuePair<string, UnknownListType> storedItemCategory in TestDict)
{
//how would i properly check the value type of an UnknownListType as a list, this is what i would guess would be the way to do it:
if (storedItemCategory.Value.GetType().GetGenericArguments()[0].IsSubclassOf(typeof(Item)))
{
//now how would i convert "storedItemCategory.Value" into a list of items before concatenating it to convertedList?
}
//else... (extracting the instance of a list of type tuple<UnknownChildInstanceType,int> would be here but isn't really needed to explain the problem)
}
I'll probably just end up reworking the Dictionary itself where the values are always in the same place If no one has an idea of how this could be implemented.
Your dictionary must be declared somewhere, for example Dictionary<string,TValueList>. Whatever TValueList is, that tells you the type for the loop variable. You have written KeyValuePair<string, UnknownListType> … did you mean that the dictionary actually has type Dictionary<string, UnknownListType> or did you mean that you don't know the type?
My guess would be that the list type, TValueList (or UnknownListType, as you call it), is IList or some other nongeneric type. Then you would simply access that IList and downcast the members to the type indicated by the string key. Something like this:
static public IList<TValue> GetConsolidatedList<TValue>(this Dictionary<string, IList> dictionary)
{
IEnumerable<IList> lists = dictionary.Where(kvp => kvp.Key == typeof(TValue).Name).Select(kvp => kvp.Value);
List<TValue> consolidated = lists.Where( list => list.Count > 0 && list[0] is ValueTuple<TValue,int>).SelectMany(list => list.Cast<(TValue,int)>()).Select( tuple => tuple.Item1).ToList();
consolidated.AddRange(lists.Where(list => list.Count > 0 && list[0] is TValue).SelectMany(list => list.Cast<TValue>()));
return consolidated;
}
Note here I am suggesting to use ValueTuple instead of Tuple. This is more efficient and also enables naming the elements of the tuple for example in the syntax (TValue value, int count)
Having said all that, it seems to me that you would be better off using more type information in the structure. It might make sense to have two dictionaries, one of type Dictionary<string,IList<IValue>> and another of type Dictionary<string,IList<(IValue, int)>>, then have your classes implement interface IValue. If you need to deal with the two dictionaries as one then just put them both into a single class that implements the desired operations.

How do I sort IList C # by date?

I have an IList:
IList[] info = new IList[2];
info[0] = Date; //List<DateTime> item
info[1] = something; //List<double> item
So, I want sort info by dates in info[0]. Like that:
Date.Sort((a, b) => a.CompareTo(b));
But when i'm trying to do it:
IEnumerable[] sortedEnum = info.OrderBy(info[0].Sort((a, b) => a.CompareTo(b)));
I get:
'System.Collections.IList' does not contain a definition for 'Sort' and no extension method 'Sort' accepting a first argument of type 'System.Collections.IList' could be found (are you missing a using directive or an assembly reference?).
Can someoene help me with this?
I think this is an X/Y problem. You're trying to solve a complex "sort two lists congruent to each-other". And ... you can do that, but it is very hard. Array.Sort has a suitable method for sorting two arrays in connection, but: not lists. You could try and do that, but frankly I think you're solving the wrong problem. If each DateTime and double is logically connected, then rather than having two lists: have one list with a composite value. For example:
var list = new List<(DateTime when, double value)>();
list.Add((dateX, valueX)); // your values...
list.Add((dateY, valueY));
list.Add((dateZ, valueZ));
list.Sort((x,y) => x.when.compareTo(y.when));
Here I'm using tuple-types, but the same thing can be done by declaring your own type to hold the composite values. You might also want to look into pre-sorted list container types, but that places more demands on the key value (uniquity, etc).
Building on Marc's
List<(DateTime when, double value) list = info[0].Zip(info[1], (d,v)=> (d,v));
And as Magnetron points out, if you don't have C#7 yet,
var list = info[0].Zip(info[1], (d,v)=> Tuple.Create(d,v));
list.Sort((x,y) => x.Item1.compareTo(y.Item1));

List of classes question c#

I have a class contain many variables, something like that
class test
{
internal int x , y ;
internal string z;
}
I created a list of this class list<test> c
I want to do the following:
test if all the list items contain the same x
get the list's item that has z = "try"
I need a quick and fast way , instead of iterate though the entire items
Any suggestion please ,
LINQ to Objects is your friend. For the first:
bool allSameX = list.All(t => t.x == list[0].x);
Test firstTry = list.First(t => t.z == "try");
Test firstTryOrNull = list.FirstOrDefault(t => t.z == "try");
The first one depends on there being at least one value of course. Alternatives might be:
bool allSameX = !list.Select(t => t.x)
.Distinct()
.Skip(1)
.Any();
In other words, once you've gone past the first distinct value of x, there shouldn't be any more. One nice aspect of this is that as soon as it spots the second distinct value, it will stop looking - as does the first line (the All version) of course.
LINQ is wonderfully flexible, and well worth looking into closely.
EDIT: If you need to do the latter test ("find an element with a particular value for z") for multiple different values, you might want a dictionary or a lookup, e.g.
// If there are duplicate z values
var lookup = list.ToLookup(t => t.z);
// If z values are distinct
var dictionary = list.ToDictionary(t => t.z);
Without some pre-work, there's no way of performing the queries you want without iterating over at least some of the list.
You can use linq. Here is a link to small examples that will help you a lot for future too http://msdn.microsoft.com/en-us/vcsharp/aa336746
You could implement a custom collection class instead of a list, and put the search smarts into this e.g.
add a method AllItemsHaveSameX() and a private bool field allItemsHaveSameX
expose a dictionary keyed by the search strings with the index of the item that has that value.
When adding/removing items:
You would re-evaluate allItemsHaveSameX
Add/remove from your private dictionary.

List of Interfaces vs. List of Derived Type - Cannot Convert Expression Type to Return Type

Why does this work:
public IList<ICoupon> GetCouponsForSite(string siteSlug)
{
var coupons = _db.Coupons.Where(x => x.Site.slug == siteSlug)
.Select(x => new Coupon(x.id));
var list = new List<ICoupon>();
foreach (var coupon in coupons)
{
list.Add(coupon);
}
return list;
}
But this does does not work (error - cannot convert expression type to return type):
public IList<ICoupon> GetCouponsForSite(string siteSlug)
{
return _db.Coupons.Where(x => x.Site.slug == siteSlug)
.Select(x => new Coupon(x.id)).ToList();
}
Because db.Coupons...ToList() returns an IList<Coupon> rather than an IList<ICoupon>. IList<Coupon> does not derive from IList<ICoupon> because C# 3 doesn't support generic variance. (C# 4 does support generic variance, but it still won't derive in this case. Consider that whoever receives an IList<ICoupon> could try to stuff a SomeEvilTypeThatImplementsICoupon into it. But an IList<Coupon> couldn't accept that because SomeEvilTypeThatImplementsICoupon doesn't derive from Coupon. See http://hestia.typepad.com/flatlander/2008/12/c-covariance-and-contravariance-by-example.html for discussion of this convertibility issue albeit in a slightly different context, and the Eric Lippert articles linked from there.)
(Your first snippet, by contrast, explicitly constructs a List<ICoupon>, which can contain anything that implements ICoupon, and then puts some Coupon objects into that list. Now if the receiver decides to poke SomeEvilTypeThatImplementsICoupon into it, all is well, because the List was built to hold any ICoupon, not just actual Coupon objects.)
It can't implicitly cast List<Coupon> to List<ICoupon>. Try this:
public IList<ICoupon> GetCouponsForSite(string siteSlug)
{
return _db.Coupons.Where(x => x.Site.slug == siteSlug)
.Select(x => new Coupon(x.id)).Cast<ICoupon>().ToList();
}
The basic reason for this is that if you had for example a class FancyCoupon : ICoupon and tried to put that into a List<Coupon> then it would fail cause FancyCoupon doesn't derive from Coupon (only ICoupon) but it should work just fine into a List<ICoupon>. So while at first glance it looks like it should be able to use one as the other there's rather important differences between the two types.
The cast call essentially iterates over the list and typecasts each one for the new list (There's a bit more to it for performance reasons under the bonnet, but for practical purposes you can think of it that way).
(Updated with fix from comments)
IQueryable<ICoupon> is not derived from IList<ICoupon>.
This is because the compiler infers ICoupon, and not Coupon, in the Select as generic type argument. So instead of an explicit cast after the Select as proposed by others (which not too efficient because it needs to iterate over all items), you can also use implicit casting (or more correctly variance) by specifying the correct Select generic types:
public IList<ICoupon> GetCouponsForSite(string siteSlug)
{
return _db.Coupons.Where(x => x.Site.slug == siteSlug)
.Select<?, ICoupon>(x => new Coupon(x.id)).ToList();
}
(You need to replace the ? with the appropriate type of the Coupons collection.)

Categories