Count of System.Collections.Generic.List - c#

ViewBag.EquipmentList = myInventoryEntities.p_Configurable_Equipment_Request_Select(Address_ID, false).Select(c => new { Value = c.Quantity + " " + c.Device_Name + " (s)", ID = c.Device_ID.ToString() }).ToList();
In Razor i want to do the following
#ViewBag.EquipmentList.Count
But Count is always == 1
I know i can iterate in a foreach but would rather a more direct approach.
Perhaps I am conceptually off?

EDIT: Okay, so now it seems like you've got past Count not executing:
But Count is always == 1
Sounds like you're always fetching a list with exactly one entry in. If that's unexpected, you should look at why you're only getting a single entry - start with debugging into the code... this doesn't sound like a Razor problem at all.
If your value were really a List<T> for some T, I believe it should be fine. The expression ViewBag.EquipmentList.Count would evaluate dynamically at every point.
In other words, if you're really, really using the assignment code shown, it should be okay.
If, however, the value is just some implementation of IEnumerable<T> which doesn't expose a Count property, then you'd need to use the Enumerable.Count() extension method - and you can't use normal "extension method syntax" with dynamic typing. One simple fix would be to use:
Enumerable.Count(ViewBag.EquipmentList)
... which will still use dynamic typing for the argument to Enumerable.Count, but it won't have to find the Count() method as an extension method.
Alternatively, make sure that your value really is a List<T>. If it's actually an array, you should be able to change the code to use the Length property instead.

#ViewBag.EquipmentListNI.Count()

Related

How does Linq know the name of an element?

I’ve solved a C# beginner Kata on Codewars, asking to return a string[] with only 4-character names. I used a list that is filled in an if statement and then converted back to a string and returned.
My question is regarding the best practice solution below, which is presented later.
I understand that the same string[] that comes as an argument is refilled with elements and returned. But how does the program know that each element of the array is called “name”, as it’s never mentioned before?
Does linq know that a variable with a singular name is an element of a plural name group, here “names”?
Thanks for helping out!
using System;
using System.Collections.Generic;
using System.Linq;
public static class Kata {
public static IEnumerable<string> FriendOrFoe (string[] names) {
return names.Where(name => name.Length == 4);
}
}
I understand that the same string[] that comes as an argument is refilled with elements and returned
I'll address this briefly, because it's not the question you're asking. This isn't true - no refilling of anything occurs. The original array is unaltered and a Where is a loop that runs over the array and selectively emits items from it when the test presented to it evaluates to true for that item. The way it does this is via a special construct called a yield return which is a way of allowing code to return from a method and then re-enter it and carry on from where it left off before, rather than starting all over again from the beginning of the method. There is only ever one array, and the looping/testing is not performed unless you start reading from the set of strings produced by the Where. If you want to know more about that, drop a comment.
Moving on..
Does linq know that a variable with a singular name is an element of a plural name group, here “names”?
No; the IDE knows the variable name because that's what you chose to call it just after the Where(
Perhaps it would help to link it to something you already know. It would be perfectly acceptable to write this code:
public static class Kata {
public static IEnumerable<string> FriendOrFoe (string[] names) {
return names.Where(IsNameOfLengthFour);
}
static bool IsNameOfLengthFour(string name){
return name.Length == 4;
}
}
Where demands some method be supplied that takes a string and returns a boolean. It demands that the input be a string because it's being called on names which is an array of string. If it were ints in the array, the method passed to Where would have to take an int
In C# there's often a push to make things more compact, so to get rid of all that wordiness above, we have a much more compact form of writing method bodies. Let's reduce our wordy version:
static bool IsNameOfLengthFour(string name){
return name.Length == 4;
}
We can chuck out the return type, because we can guess that from the type being returned. We can get rid of static too, and just assume static if we're calling it from inside another static, or not if we're not. We can ditch the input type too, because we can guess that from the type going in.
IsNameOfLengthFour(name){
return name.Length == 4;
}
If we have a special syntx that is only one line and must be a value that is auto returned, we can get rid of the return, and the {} because it's only one line, so we don't need to fence off multiple statements:
IsNameOfLengthFour(name) => name.Length == 4
Now, we don't actually need a method name any more either if we're going to use this in some place where a name is irrelevant, and we really don't need () for a single argument either:
name => name.Length == 4
And that's enough of an expression for the compiler to be able to form a method out of it, and plumb it into something that expects a method taking a string and returning a boolean. We've thrown away all the fluff of a method that we humans like (names and identifiers) and given the compiler just the raw nuts and bolts it needs - the logic of the method. The compiler will recreate the rest of the fluff when it wires it all together for us; we won't ever be able to call this mini-method from elsewhere in our code but we don't care. We got what we wanted, which is a nice compact way of expressing the logic:
Where(n => n.Length==4);
You did a good job, calling the argument to this mini-method something sensible. I see x used a lot and it gets really confusing when what X is changes.. For example:
names
.Where(name => ...)
.GroupBy(name => ...)
.Select(g => g.First())
.Where(name => ...)
Where works on your array of names so calling the argument to the delegate name or n is a good idea. Where will filter it down but ultimately it still emits a set of strings that are names, so it's still a good idea to call it name on the way into a GroupBy.. But a GroupBy produces a set of IGrouping, not a set of string so the thing coming our of a GroupBy is no longer a name.. In the next Select I call it g to reflect that it's a grouping, not a name, but I then take the first item in the grouping which is, actually, a name.. So in the final Where I go back to calling the input argument name to reflect what it's back to being..
When LINQ statements get much more complicated, it really helps to name these arguments well
Note: in this answer I've used words like "list" or "set" and I mean those in the general English sense that an "array is a list of ..", not a specifically C# List<xxx> or HashSet<xxx> sense. If you see lowercase words that align with C# types, they are not intended to refer to that specific type
I understand that the same string[] that comes as an argument is refilled with elements and returned.
No, absolutely not. A new sequence of strings is returned based on the input array. The input array is not modified or changed in any way.
But how does the program know that each element of the array is called “name”, as it’s never mentioned before?
name is a parameter to an anonymous function. The name parameter is a string based on context. This could be x or ASDASDASD or whatever you want, but here we use name since we have, on each call, one "name" from names.
Thus,
names is an array of strings passed into the function
the .Where returns a new IEnumerable<string> from the current array based on a predicate function (e.g. returns true for a match, false to omit)
The predicate name => name.Length == 4 takes a string and returns true if the string is length 4
The return from the function is the strings from names that are exactly 4 characters in length

How to explicitly state the types when grouping in LINQ?

I'm playing around with GroupBy(...) and I realize that, although working, I prefer not to use var. Call me anal but I like to know what type I have when I have it. (Of course, I'm not an ideologue and when the syntax is making ones eyes bleed, I do use var. Still, it's nice to know how to explicitize it, should ones urge emerge.)
var grouping = array.GroupBy(element => element.DayOfWeek);
foreach (var group in grouping)
{
Console.WriteLine("Group " + group.Key);
foreach (var value in group)
Console.WriteLine(value.Start);
}
According to the intellisense, I'm generating something of type IGrouping but when I tried to type that in explicitly, weird stuff happened. I've arrived at the following.
IEnumerable<IGrouping<DayOfWeek, TimeInfo>> grouping
= array.GroupBy(element => element.DayOfWeek);
foreach (IGrouping<DayOfWeek, TimeInfo> group in grouping)
{
Console.WriteLine("Group " + group.Key);
foreach (TimeInfo value in group)
Console.WriteLine(value.Start);
}
My question is twosome. Is the below the correct and most narrow scope for the produced result? If not, how can I tight it up additionally?
If it is so, however, I'd like to know if there's a better way to approach the task. I only need to put my elements from the array into different bins with respect to day of the weeks (or any other condition in the actual production). I don't really need the key, just a way to make my 1D array into 2D array of arrays. Something like an opposite to SelectMany, so to speak. (No extensive answer needed - just a keyword to google away.)
Is the below the correct and most narrow scope for the produced result?
Well, IGrouping<TKey,TElement> implements IEnumerable<TElement> so you could do:
IEnumerable<IEnumerable<TimeInfo>> grouping =
= array.GroupBy(element => element.DayOfWeek);
Note that the data (including the key values) is still in the concrete data structure; you're just interfacing with is as a collection of collections.
From there you can convert to arrays by using ToArray():
TimeInfo[][] groups =
grouping.Select(g => g.ToArray()).ToArray();
I have done exactly this before to make code more readable that deals with groupings. Often making sure a foreach or class property declares the types of the IGrouping explicitely so the type is clear. As covered here, there is no concrete type that implements IGrouping, so there is nothing more concrete that you can use, so I would say as far as declaring the result of a groupby, there's nothing more you can do to tighten it down: Is it possible to create some IGrouping object
You can also use ToDictionary to create something that is more familiar to many developers, but each value would actually be a list, which might be a bit odd.
As Stanley points out you can use Select with ToArray, or you can use ToList to create a List of Lists.

Modify current source using lambda

Lets assume that I have an IEnumerable<MyType> called myList. I would like to remove some items from the list using a lambda expression.
Currently, I do it in the following way:
myList = myList.Where(x=>x.SomeProp == 1);
I would like to do something like:
myList.Remove(x=>x.SomeProp != 1);
I know that Remove() doesn't exist by default, but does a similar method exist? Or do I have to write an extension method?
IEnumerable<T> itself doesn't expose any mutating operations - so you can't expose a Remove operation. If you're trying to remove items from a List<T> you could use List<T>.RemoveAll though.
If you want a sort of "inverse where" which excluded rather than included items, then you could write that very easily. It's not clear that it would really be advantageous to do so though - you can usually invert the logic of a predicate very easily, and while Where is familiar to other programmers, your new extension method wouldn't be.
I definitely wouldn't call such an operation Remove though - that sounds like it's a mutating operation. I'd probably call it something like ExceptWhere - so you'd have:
var adults = people.ExceptWhere(person => person.Age < 18);
as an example.

Resharper: Possible Multiple Enumeration of IEnumerable

I'm using the new Resharper version 6. In several places in my code it has underlined some text and warned me that there may be a Possible multiple enumeration of IEnumerable.
I understand what this means, and have taken the advice where appropriate, but in some cases I'm not sure it's actually a big deal.
Like in the following code:
var properties = Context.ObjectStateManager.GetObjectStateEntry(this).GetModifiedProperties();
if (properties.Contains("Property1") || properties.Contains("Property2") || properties.Contains("Property3")) {
...
}
It's underlining each mention of properties on the second line, warning that I am enumerating over this IEnumerable multiple times.
If I add .ToList() to the end of line 1 (turning properties from a IEnumerable<string> to a List<string>), the warnings go away.
But surely, if I convert it to a List, then it will enumerate over the entire IEnumerable to build the List in the first place, and then enumerate over the List as required to find the properties (i.e. 1 full enumeration, and 3 partial enumerations). Whereas in my original code, it is only doing the 3 partial enumerations.
Am I wrong? What is the best method here?
I don't know exactly what your properties really is here - but if it's essentially representing an unmaterialized database query, then your if statement will perform three queries.
I suspect it would be better to do:
string[] propertiesToFind = { "Property1", "Property2", "Property3" };
if (properties.Any(x => propertiesToFind.Contains(x))
{
...
}
That will logically only iterate over the sequence once - and if there's a database query involved, it may well be able to just use a SQL "IN" clause to do it all in the database in a single query.
If you invoke Contains() on a IEnumerable, it will invoke the extension method which will just iterate through the items in order to find it. IList has real implementation for Contains() that probably are more efficient than a regular iteration through the values (it might have a search tree with hashes?), hence it doesn't warn with IList.
Since the extension method will only be aware that it's an IEnumerable, it probably can not utilize any built-in methods for Contains() even though it would be possible in theory to identify known types and cast them accordingly in order to utilize them.

Probably BAD coding style ... please comment

I am checking whether the new name already exists or not.
Code 1
if(cmbxExistingGroups.Properties.Items.Cast<string>().ToList().Exists(txt => txt==txtNewGroup.Text.Trim())) {
MessageBox.Show("already exists.", "Add new group");
}
Otherwise I could have written:
Code 2
foreach(var str in cmbxExistingGroups.Properties.Items)
{
if(str==txtNewGroup.Text) {
MessageBox.Show("already exists.", "Add new group");
break;
}
}
I wrote these two and thought I was exploiting language features in code 1.
...and yes: both of them work for me ... I am wondering about the performance :-/
I appreciate the cleverness of the first sample (assuming it works), but the second one is a lot easier for the next person who has to maintain the code to figure out.
Sometimes just a little indentation makes a world of difference:
if (cmbxExistingGroups.Properties.Items
.Cast<string>().ToList()
.Exists
(
txt => txt==txtNewGroup.Text.Trim()
))
{
MessageBox.Show("already exists.", "Add new group");
}
Since your using a List<String>, you might as well just drop the Exists predicate and use Contains...use Exists when comparing complex objects by unique values.
I've quoted it before but I'll do it again:
Write your code as if the person maintaining it is a homicidal maniac
who knows where you live.
would
cmbxExistingGroups.Properties.Items.Contains(text)
not work instead?
There are a few things wrong here:
1) The two bits of code don't do the same thing - the first looks for the trimmed version of txtNewGroup, the second just looks for txtNewGroup
2) There's no point in calling ToList() - that just make things less efficient
3) Using Exists with a predicate is overkill - Contains is all you need here
So, the first could easily come down to:
if (cmbxExistingGroups.Properties.Items.Cast<string>.Contains(txtNewGroup.Text))
{
// Stuff
}
I'd probably create a variable to give "cmbxExistingGroups.Properties.Items.Cast" a meaningful, simple name - but then I'd say it's easier to understand than the explicit foreach loop.
The first code bit is fine, except instead of calling Enumerable.ToList() and List<T>.Exists(), you should just call Enumerable.Any() -- it does a lazy evaluation, so it never allocates the memory for the List<T>, and it will stop enumerating cmbxExistingGroups.Properties.Items and casting them to string. Also, calling the trim from inside that predicate means it happens for every item it looks at. It would be best to move it out to the outer scope:
string match = txtNewGroup.Text.Trim();
if(cmbxExistingGroups.Properties.Items.Cast<string>().Any(txt => txt==match)) {
MessageBox.Show("already exists.", "Add new group");
}
Verbosity in coding is not always bad at all. I prefer the second code snippet a lot over the first one. Just imagine you would have to maintain (or even change the functionality of) the first example... um.
Well, if it were me, it would be a variation on 2. Always prefer readability over one-liners. Additionally, always extract a method to make it clearer.
your calling code becomes
if( cmbxExistingGroups.ContainsKey(txtNewGroup.Text) )
{
MessageBox.Show("Already Exists");
}
If you define an extension method for Combo Boxes
public static class ComboBoxExtensions
{
public static bool ContainsKey(this ComboBox comboBox, string key)
{
foreach (string existing in comboBox.Items)
{
if (string.Equals(key, existing))
{
return true;
}
}
return false;
}
}
First, they're not equivalent. The 1st sample does a check against txtNewSGroup.Text.Trim(), the 2nd omits trim. Also, the 1st casts everything to a string, whereas the second uses whatever comes out of the iterator. I assume that's an object, or you wouldn't have needed the cast in the 1st place.
So, to be fair, the closest equivalent to the 2nd sample in the LINQ style would be:
if (mbxExistingGroups.Properties.Items.Cast<string>().Contains(txtNewGroup.Text)) {
...
}
which isn't too bad. But, since you seem to be working with old style IEnumerable instead of new fangled IEnumerable<T>, why don't we give you another extension method:
public static Contains<T>(this IEnumerable e, T value) {
return e.Cast<T>().Contains(value);
}
And now we have:
if (mbxExistingGroups.Properties.Items.Contains(txtNewGroup.Text)) {
...
}
which is pretty readable IMO.
I would agree, go with the second one because it will be easier to maintain for anybody else who works on it and when you come back to that in 6-12 months, it will be easier to remember what you were doing.
both of them works for me ..i am wonodering about the performance
I see no one read the question :) I think I see what you're doing (I don't use this language). The first tries to generate the list and test it in one shot. The second does an explicit iteration and can "short circuit" itself (exit early) if it finds the duplicate early on. The question is whether the "all at once" is more efficient due to the language implementation.
The second of the two would perform better, and it would perform the same as other people's samples that use Contains.
The reason why the first one uses an extra trim. plus a conversion to list. so it iterates once for conversion, then starts again to check using exists, and does a trim each time, but will exit iteration if found. The second starts iterating once, has no trim, and will exit if found.
So in short the answer to your question is the second performs much better.
From a performance point of view:
txtNewGroup.Text.Trim()
Do your control interaction/string manipulation outside of the loop - one time, instead of n times.
I imagine that on the WTF's per minute scale, the first would be off the chart. Count the dots, any more than two per line is a potential problem

Categories

Resources