Why doesn't the Lookup that results from GroupBy have Lookup properties? - c#

I am trying to understand the System.Linq.Lookup class. When calling GetType(), the following displays:
System.Linq.Lookup`2+Grouping[System.Object,System.Data.DataRow]
What does the back tick mean?
What does the 2+ mean?
What is the Grouping class that follows the 2+?
Further, in the Fiddle's Inspect() method, why does lookup have a Key property rather than a Count and Item property?
The ultimate goal is to learn how to bind this to a nested ASP.NET repeater. We've already succeeded by casting the result to a Dictionary<string, DataTable>. We suspect, though, that it's possible to bind directory to the GroupedEnumerable once we understand its structure.
Fiddle
public static class Program
{
public static void Main()
{
var dt = GetData();
var enumerable = dt.AsEnumerable();
var grouped = enumerable.GroupBy(dr => dr["Name"]);
Inspect(grouped);
}
public static void Inspect(IEnumerable<IGrouping<object, DataRow>> grouped)
{
LogType("grouped", grouped);
var lookup = grouped.FirstOrDefault();
LogType("lookup", lookup);
LogType("key", lookup.Key);
var item = lookup.FirstOrDefault();
LogType("item", item);
}
public static void LogType(string label, object v)
{
Console.WriteLine("\n" + label.PadRight(10) + v.GetType());
}
public static DataTable GetData()
{
DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("StartDate");
dt.Columns.Add("EndDate");
for(var i = 0; i < 10; ++i)
{
var row = dt.NewRow();
row["Name"] = i % 2;
row["StartDate"] = DateTime.Now;
row["EndDate"] = DateTime.Now;
dt.Rows.Add(row);
}
return dt;
}
}
Output
grouped System.Linq.GroupedEnumerable`3[System.Data.DataRow,System.Object,System.Data.DataRow]
lookup System.Linq.Lookup`2+Grouping[System.Object,System.Data.DataRow]
key System.String
item System.Data.DataRow
Edit
Forked Fiddle that retrieves the values from the GroupedEnumerable.
Answers in my own words:
What does the back tick mean? The back tick indicates the number of type parameters that a class takes. In this case, it says that the Lookup class takes two type parameters.
What does the 2+ mean? The 2 belongs to the back tick not the the +. The plus means that we're accessing a class that's nested within another class. In this case, it means that we're accessing the Grouping class that's nested within a Lookup class.
What is the Grouping class that follows the 2+? It's a class nested within the Lookup.
Further, in the Fiddle's Inspect() method, why does lookup have a Key property rather than a Count and Item property? The lookup has a Key property because it isn't a Lookup; it's a Grouping that's nested inside a Lookup.

System.Linq.Lookup`2+Grouping[System.Object,System.Data.DataRow]
System.Linq.Lookup`2 is represented in C# as System.Linq.Lookup<T,U> (the back tick means the class is a generic and the number is the number of generic parameters).
The +Grouping means that there is a class defined inside of the System.Linq.Lookup`2 class called Grouping.
The two types inside the square brackets are the two types that the generic (System.Linq.Lookup) closes over.
So the full type, written in C# looks like this:
System.Linq.Lookup<object, System.Data.DataRow>.Grouping
The type doesn't need an Items property because it implements IEnumerable, which means the type itself can be iterated over (just like any other IEnumerable such as List<T>).
Not all lists/collections have a Count property, there is nothing that says they have to. You can get the count by calling the Count() extension method, but that could cause the entire enumerable to be iterated over, which may or may not have a significant performance cost.

This is CLR standard type syntax.
`2 means that the type has two generic parameters.
+ means a type that is nested inside another type.
In this case, it's telling you that the Grouping class is nested inside a Lookup class with two generic parameters.
As you can see from the source, the only public property that it defines is Key.

Related

How to Get Value in Result View C#?

I want to get value in my object. When I look my inside of object, I can see my value in Result View IEnumerable. But, I can't get this values.
When I write "value."; just see "ToString, GetType, GetHashCode and Equals". I try GetType and get value but I can't. Because, I haven't name of values. How solve we this problem?
The IEnumerable uses syntactic sugar in the background. IEnumerable I feels like a list but behaves differently. The bigest different is that IEnumerable is lazy evaulated. This means only the requested object will be loaded into the memory. The interface hase a CurrentItem property that is accessed by foreach loop.
Here are some options to access the underlaying value:
User foreach
foreach (var value in myEnumerableCollection)
{
Console.WriteLine(value);
}
Use LINQ
var value = myEnumerableCollection.FirstOrDefault(x => x == someSearchTerm);
Cast the enumartion to a list and use the list methods and use indexers or other list methods to grab the value. A small warning, this will force the collection load every element into the memory. If it is large this may cause some issues. For example loading x million rows of db table with no pagination.
int index = 1;
var value = myEnumerableCollection.ToList()[index];
You can cast your value to IEnumerable T, where T - is your type, for example:
if (value is IEnumerable<int> resultList)
{
foreach (int item in resultList)
{
Console.WriteLine(item);
}
};

C# - Getting the 3 lowest values in a List, measured by a public property of the objects within the List

Sorry if my terminology is not great, I'm not a professional programmer.
I have a List< Something >, whereby the 'Something' is a struct. This struct contains objects, which each have their own public properties/fields in the classes. I want to sort the list in order - but by the values found in these nested properties/fields. Then I want to return a list of these values, not the structs.
I know this is very confusing but I've had trouble trying to do it. At the moment I just get a list returned with a count of 20 (which is the full data set I'm using), but I want the 3 values only with the smallest value.
For context and further explanation, here is some code I'm using:
// Returns 3 nearest stations to the location specified
public static List<TrainStation> nearbyStations(GeoCoordinate location)
{
List<StationWalk> stations = new List<StationWalk>();
foreach (TrainStation s in All)
{
stations.Add(new StationWalk(s, new Walk(location, s.location)));
}
// return 3 TrainStation objects that have the lowest StationWalk.Walk.duration values corresponding with them in the StationWalk struct
stations.OrderBy(walks => walks.walk.duration).Take(3);
List<TrainStation> returnList = new List<TrainStation>();
foreach (StationWalk s in stations)
{
returnList.Add(s.station);
}
return returnList;
}
private struct StationWalk
{
public StationWalk(TrainStation station, Walk walk)
{
this.station = station;
this.walk = walk;
}
public TrainStation station;
public Walk walk;
}
'Walk' is a class that contains a 'duration' field. This represents the time it takes to walk. More specifically, my overall goal here is to figure out which 3 walks are the fastest walks out of all 20 in the list. But the 'walks' are properties of the StationWalk struct, and the 'duration' is a property of the Walk.
How would I go about doing this? Really sorry if this isn't well explained, it's confusing to myself despite writing it myself, yet alone trying to explain it to others.Appreciate any help.
The OrderBy and Take both return a new collection, they do not modify the existing collection, so you would need to store the reference to new collection returned by the methods like:
stations = stations.OrderBy(walks => walks.walk.duration).Take(3).ToList();
and if you want to keep reference to the original list for further usage down in your code, then just store the result in a local variable:
var lowestThreeStations = stations.OrderBy(walks => walks.walk.duration).Take(3).ToList();

How to find specific object from list in C#?

How is it possible to find a specific object from a list?
Lets say i have a function that takes an object and a list that contains objects of this type and returns the number at which position the specific object is found.
The only way i could think of a solution is to run the list through with a foreach loop, but isn't there a better way?
Thanks
You can use the IndexOf(T item) method:
myList.IndexOf(myItem);
It returns the index of the first occurrence of the item.
The only way i could think of a solution is to run the list through with a foreach loop
Generally, you need a loop (a for or foreach) to find an object in a list. You could use it directly, or through a function that iterates over list elements, but there is going to be a loop. There is no way around it: unless you know something special about the way the elements of the array are arranged, you have to look at them all.
One case of knowing something special about arrangement of elements is knowing that an array is sorted. If this is the case, and when you know the value of the attribute on which the element is sorted, you can find the element much faster by using binary search.
You could use linq expressions
List.where(condition)
Or
List.Select(condition).FirstOrDefault
Based on search condition it will return the item you want.
You can use method IndexOf or if you use a special condition then you can use method
public int FindIndex(Predicate<T> match);
where match is delegate
public delegate bool Predicate<T>(T obj);
In fact it is similar to standard C++ algorithm std::find_if
To see whether object is there You might just need List<T>.Contains method
It states,
Determines whether an element is in the List.
And you need to use it like List<T>.Contains(T type item) , where T is the same type of List and item you need to compare. In your case it's a the type of Object
And to return the index you can use List<T>.IndexOf Method
Searches for the specified object and returns the zero-based index of the first occurrence within the entire List.
Simple Console program
class Program
{
static void Main(string[] args)
{
MyType a = new MyType() { id = 10 };
MyType b = new MyType() { id = 20 };
MyType c = new MyType() { id = 30 };
List<MyType> testList = new List<MyType>();
testList.Add(a);
testList.Add(b);
Console.WriteLine(testList.Contains(a)); // <= Will return true
Console.WriteLine(testList.Contains(c)); // <= Will return false
Console.WriteLine(testList.IndexOf(a)); // <= will return 0 : the index of object a
Console.ReadKey();
}
}
// A simple class
class MyType
{
private int ID;
public int id
{
get { return ID; }
set { ID = value; }
}
}

Something similar to C# .NET Generic List in java

How would be a c# .net generic list in java?
somthing like that:
public class ClientList : List<Client> { }
the answer from Nikil was perfect, I just want to add to whoever wants to create a class from the List:
public class ClientList extends ArrayList<Client>
Java's List interface (java.util.List) can be generified. In other words, instances of List can be given a type, so only instances of that type can be inserted and read from that List. Here is an example:
List<String> list = new ArrayList<String>();
This list is now targeted at only String instances, meaning only String instances can be put into this list. If you try to put something else into this List, the compiler will complain.
The generic type checks only exists at compile time. At runtime it is possible to tweak your code so that a String List has other objects that String's inserted. This is a bad idea, though.
Accessing a Generic List
You can get and insert the elements of a generic List like this:
List<String> list = new ArrayList<String>();
String string1 = "a string";
list.add(string1);
String string2 = list.get(0);
Notice how it is not necessary to cast the object obtained from the List.get() method call, as is normally necessary. The compiler knows that this List can only contain String instances, so casts are not necessary.
Iterating a Generic List
You can iterate a generic List using an iterator, like this:
List<String> list = new ArrayList<String>();
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String aString = iterator.next();
}
Notice how it is not necessary to cast the object returned from the iterator.next() next call. Because the List is generified (has a type), the compiler knows that it contains String instances. Therefore it is not necessary to cast the objects obtained from it, even if it comes from its Iterator.
You can also use the new for-loop, like this:
List<String> list = new ArrayList<String>();
for(String aString : list) {
System.out.println(aString);
}
Notice how a String variable is declared inside the parantheses of the for-loop. For each iteration (each element in the List) this variable contains the current element (current String).

how to add an associative index to an array. c#

i have an array of custom objects. i'd like to be able to reference this array by a particular data member, for instance myArrary["Item1"]
"Item1" is actually the value stored in the Name property of this custom type and I can write a predicate to mark the appropriate array item. However I am unclear as to how to let the array know i'd like to use this predicate to find the array item.
I'd like to just use a dictionary or hashtable or NameValuePair for this array, and get around this whole problem but it's generated and it must remain as CustomObj[]. i'm also trying to avoid loading a dictionary from this array as it's going to happen many times and there could be many objects in it.
For clarification
myArray[5] = new CustomObj() // easy!
myArray["ItemName"] = new CustomObj(); // how to do this?
Can the above be done? I'm really just looking for something similar to how DataRow.Columns["MyColumnName"] works
Thanks for the advice.
What you really want is an OrderedDictionary. The version that .NET provides in System.Collections.Specialized is not generic - however there is a generic version on CodeProject that you could use. Internally, this is really just a hashtable married to a list ... but it is exposed in a uniform manner.
If you really want to avoid using a dictionary - you're going to have to live with O(n) lookup performance for an item by key. In that case, stick with an array or list and just use the LINQ Where() method to lookup a value. You can use either First() or Single() depending on whether duplicate entries are expected.
var myArrayOfCustom = ...
var item = myArrayOfCustom.Where( x => x.Name = "yourSearchValue" ).First();
It's easy enough to wrap this functionality into a class so that external consumers are not burdened by this knowledge, and can use simple indexers to access the data. You could then add features like memoization if you expect the same values are going to be accessed frequently. In this way you could amortize the cost of building the underlying lookup dictionary over multiple accesses.
If you do not want to use "Dictionary", then you should create class "myArrary" with data mass storage functionality and add indexers of type "int" for index access and of type "string" for associative access.
public CustomObj this [string index]
{
get
{
return data[searchIdxByName(index)];
}
set
{
data[searchIdxByName(index)] = value;
}
}
First link in google for indexers is: http://www.csharphelp.com/2006/04/c-indexers/
you could use a dictionary for this, although it might not be the best solution in the world this is the first i came up with.
Dictionary<string, int> d = new Dictionary<string, int>();
d.Add("cat", 2);
d.Add("dog", 1);
d.Add("llama", 0);
d.Add("iguana", -1);
the ints could be objects, what you like :)
http://dotnetperls.com/dictionary-keys
Perhaps OrderedDictionary is what you're looking for.
you can use HashTable ;
System.Collections.Hashtable o_Hash_Table = new Hashtable();
o_Hash_Table.Add("Key", "Value");
There is a class in the System.Collections namespace called Dictionary<K,V> that you should use.
var d = new Dictionary<string, MyObj>();
MyObj o = d["a string variable"];
Another way would be to code two methods/a property:
public MyObj this[string index]
{
get
{
foreach (var o in My_Enumerable)
{
if (o.Name == index)
{
return o;
}
}
}
set
{
foreach (var o in My_Enumerable)
{
if (o.Name == index)
{
var i = My_Enumerable.IndexOf(0);
My_Enumerable.Remove(0);
My_Enumerable.Add(value);
}
}
}
}
I hope it helps!
It depends on the collection, some collections allow accessing by name and some don't. Accessing with strings is only meaningful when the collection has data stored, the column collection identifies columns by their name, thus allowing you to select a column by its name. In a normal array this would not work because items are only identified by their index number.
My best recommendation, if you can't change it to use a dictionary, is to either use a Linq expression:
var item1 = myArray.Where(x => x.Name == "Item1").FirstOrDefault();
or, make an extension method that uses a linq expression:
public static class CustomObjExtensions
{
public static CustomObj Get(this CustomObj[] Array, string Name)
{
Array.Where(x => x.Name == Name).FirstOrDefault();
}
}
then in your app:
var item2 = myArray.Get("Item2");
Note however that performance wouldn't be as good as using a dictionary, since behind the scenes .NET will just loop through the list until it finds a match, so if your list isn't going to change frequently, then you could just make a Dictionary instead.
I have two ideas:
1) I'm not sure you're aware but you can copy dictionary objects to an array like so:
Dictionary dict = new Dictionary();
dict.Add("tesT",40);
int[] myints = new int[dict.Count];
dict.Values.CopyTo(myints, 0);
This might allow you to use a Dictionary for everything while still keeping the output as an array.
2) You could also actually create a DataTable programmatically if that's the exact functionality you want:
DataTable dt = new DataTable();
DataColumn dc1 = new DataColumn("ID", typeof(int));
DataColumn dc2 = new DataColumn("Name", typeof(string));
dt.Columns.Add(dc1);
dt.Columns.Add(dc2);
DataRow row = dt.NewRow();
row["ID"] = 100;
row["Name"] = "Test";
dt.Rows.Add(row);
You could also create this outside of the method so you don't have to make the table over again every time.

Categories

Resources