Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have array of objects and I would like to find index of some specific object inside this array:
int ix = Array.IndexOf(products, products.Where(item => item != null && item.Id == "xxx").FirstOrDefault());
Item with Id="xxx" doesn't exists, but the ix result is 1.
So, I guess that default for int is 1. How can I know if 1 belongs to first item or default value? It would be nice if I can set default value to -1.
At the end I have done it with findIndex method, but would like to know how to do it with indexOf method.
So you have two parts of one problem. First, you want to find a product:
var product = products.FirstOrDefault(item => item != null && item.Id == "xxx");
And when that product is found, you want to find its index in the products collection:
int index = Array.IndexOf(products, product);
You're halfway there using FirstOrDefault(). If a product with Id "xxx" does not exist, product will be null. So you can check for that and skip IndexOf() for null:
if (product == null)
{
return -1;
}
else
{
return Array.IndexOf(products, product);
}
The fact that your current code returns 1, means that products[1] is null.
Per Microsoft:
Sometimes the value of default(TSource) is not the default value that you want to use if the collection contains no elements. Instead of checking the result for the unwanted default value and then changing it if necessary, you can use the DefaultIfEmpty(IEnumerable, TSource) method to specify the default value that you want to use if the collection is empty. Then, call First(IEnumerable) to obtain the first element.
However, I'm not so sure that's your issue. Your code isn't syntactically correct (you're missing a ')' somewhere), but it appears you're calling FirstOrDefault() after your Where(). This will either return an element or null. Since you said an item with id "xxx" doesn't exist, it's going to check for the index of null in your array. The default value for indexOf is (again, per Microsoft) "the lower bound of the array minus 1." This should return -1 (I'd hope) instead of 1.
Conclusion: take a better look at your code and see what's really going on. Break up this linq statement into two different parts.
var item = products.Where(item => item != null && item.Id == "xxx").FirstOrDefault();
int ix = Array.IndexOf(products, item);
Then step through your code to check the values of everything. I'm sure you will find your issue, and it won't be what you expected.
If you want to call FirstOrDefault on a struct but the default value is the same as a valid one, here's one thing you can do:
(I won't use your code as the missing parenthesis prevents from knowing what your goal is)
myCollection.Where(myCondition).Cast<int?>().FirstOrDefault();
This way, 0 would be the first correct value, and null would mean that there is no correct values.
First or default returns the first element (in this case, the first item found on the where conditions) OR, the default value.
This would return an OBJECT if conditions are met (the first object that mets the condition).
However, if conditions aren't met, it would return null (the default value of an OBJECT),
soo your code would be trying to find indexOf(products,null).. that would be an NullReferenceException.
The firstOrDefault is doing his job under the OBJECT type that is inside the array.
After this, the result is passed as parameter on the method indexOf.
"indexOf" will return the index of the first object on the "where" condition.
If not found, indexOf will return -1.
By the way, u're missing an parenthesis.
Related
I've analysed an XSD document inside which are some optional elements.
Within the produced C# code I find every int, decimal, datetime,... elements with an additional field xxxFieldSpecified. I understand this is for types not supporting null so the framework can know whether or not the element has been set and be used.
Is there however, a way to identify these fields when generating the class so I can automatically add a reference to this additional field when setting the field (using its property) instead of having to set the additional field all the time when setting the property, marking the property as set.
Also, when analysing the types inside a XmlShemaSet we know whether an element is an array (ArrayRank != 0). However, ArrayRank is always either 0 or 1 though sometimes the element is a multidimentional array, and ArrayRank should say 2 for instance...
Is tehre a way to identify multidimentional arrays produced using ArrayRank or any other property or field ?
For question 1 (optional elements) I found a way by when I find a property I check the list of fields looking for the propertyname+"FieldSpecified".
CodeMemberProperty m = (CodeMemberProperty)member;
if (m.HasSet)
{
// check if optional search for <name>FieldSpecified field
bool optional = false;
foreach (CodeTypeMember mtb in codeType.Members)
if (mtb is CodeMemberField)
if (optional = (0 == string.Compare(m.Name + "FieldSpecified", mtb.Name, true)))
break;
// if optional update setting flag when the property is set
if (optional)
{
// set ...FieldSpecified when setting the property
CodeAssignStatement cas = new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), m.Name + "FieldSpecified"), new CodePrimitiveExpression(true));
m.SetStatements.Add(cas);
}
}
Probably not very smart but efficient.
If anybody has another way to do it...
Second question (multidimentional arrays) remains open.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
In what cases is each solution preferred over the other?
Example 1:
if (personList.Any(x => x.Name == "Fox Mulder"))
{
this.Person = personList.Single(x => x.Name == "Fox Mulder");
}
Example 2:
var mulder = personList.SingleOrDefault(x => x.Name == "Fox Mulder");
if (mulder != null)
{
this.Person = mulder;
}
Both Single and SingleOrDefault will enumerate the collection beyond the first matching result to verify that there is exactly one element matching the criteria, stopping at either the next match or the end of the collection. The first example will be slightly slower, since the Any call will enumerate enough of the collection (possibly all of it) to determine whether any elements meet the criteria, stopping at either the first match or the end of the collection.
There is one other critical difference: the first example could throw an exception. Single will return the matching element if there is exactly one, and throw an exception otherwise. Checking with Any does not verify this; it only verifies that there is at least one.
Based one these two reasons (primarily/especially the second reason), the SingleOrDefault approach is preferable here.
So, there are three cases here.
Case 1: No items match the condition
Option 1: .Any enumerates the entire set and returns false; .Single never executes.
Option 2: .SingleOrDefault enumerates the entire set and returns null.
Options essentially equivalent.
Case 2: Exactly one item matches the condition
Option 1: Any enumerates enough of the set to find the single match (could be the first item, could be the entire set). Next, Single enumerates the entire set to find that one item and confirm that no others match the condition.
Option 2: SingleOrDefault enumerates the entire set, returns the only match.
In this case, option 2 is better (exactly one iteration, compared to (1, 2] iterations)
Case 3: More than one element matches the condition
Option 1: Any enumerates enough to find the first match. Single enumerates enough to find the second match, throws exception.
Option 2: SingleOrDefault enumerates enough to find the second match, throws exception.
Both throw exceptions, but option 2 gets there more quickly.
Option 3:
this.Person = personList.FirstOrDefault(x => x.Name == "Fox Mulder");
if using Entity Framework and name is the primary key, then:
this.person = db.personList.Find("Fox Mulder");
Both of these work if this.Person is null coming in, or if the person isn't found, you expect this.Person to be overwritten with null. FirstOrDefault is the fastest since it will stop at the first record that matches instead of iterating through the entire collection, but it won't throw an exception if multiple are found. The entity framework solution is even better in that case because Find will use the EF cache, possibly not even having to hit the data source at all.
Extrapolating from the is v. as guidelines:
See below, from Casting vs using the 'as' keyword in the CLR:
// Bad code - checks type twice for no reason
if (randomObject is TargetType)
{
TargetType foo = (TargetType) randomObject;
// Do something with foo
}
By using Any and Single, you're also checking the list twice. And the same logic would seem to apply: Not only is this checking twice, but it may be checking different things, i.e., in a multi-threaded application the list could be different between the check and the assignment. In extreme cases the item found with Any might no longer exist when the call to Single is made.
Using this logic, I would go favor example two in all cases until given proof otherwise.
I have a problem which is already solved, but I don't know what really happens. Here is the simplified task: I have a list of records. The records consists of 2 fields, a key and a value. All keys are different. I want to sort them, so
I have a row with empty string as key, that should be in the first place.
The come the rows in which the value contains "Key not found" in alphabetical order by key
Then the rest of the rows in alphabetical order by key.
So I made this class:
private class RecordComparer : IComparer<GridRecord>
{
public int Compare(GridRecord x, GridRecord y)
{
if (x.Key == String.Empty)
return -1;
else if (y.Key == String.Empty)
return 1;
else if (x.Value.Contains("Key not found:") && !y.Value.Contains("Key not found:"))
return -1;
else if (!x.Value.Contains("Key not found:") && y.Value.Contains("Key not found:"))
return 1;
else return (x.Key.CompareTo(y.Key));
}
}
When I try to use it, I got Comparer (or the IComparable methods it relies upon) did not return zero when Array.Sort called x. CompareTo(x). x: '' x's type: 'GridRecord' The IComparer:
The error doesn't always appear, sometimes(usually when I use it first time in my program) it works fine. Second or third call crashes.
Inserting
if (x.Key == y.Key)
return 0;
in the begginning of the Compare function above solved the problem, everything works fine. Why?
If you compare {Key=""} with anything, you are currently returning -1. Even if you are comparing it with itself. When you compare something with itself (or something semantically equivalent to the same), you are supposed to return 0. That is what the error is about.
It is wise to enforce total order in your custom comparer. One of the requirements for total order is reflexivity: for any x Compare(x, x) must be equal to zero. This property is required, for example, when comparer is used to sort an array with non-unique values.
Some libraries may do additional checks for custom comparers. There is no point to compare the element to itself, but on the other hand such check allow the runtime to find subtle errors (like the one you made). Probably thats why you've got your error message. Fixing such errors makes your code more stable. Usually the checks like this exist in debug builds only.
This question already has answers here:
Why does IQueryable.All() return true on an empty collection?
(11 answers)
Closed 7 years ago.
var strs = new Collection<string>();
bool b = strs.All(str => str == "ABC");
The code creates an empty collection of string, then tries to determine if all the elements in the collection are "ABC".
If you run it, b will be true.
But the collection does not even have any elements in it, let alone any elements that equal to "ABC".
Is this a bug, or is there a reasonable explanation?
It's certainly not a bug. It's behaving exactly as documented:
true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false.
Now you can argue about whether or not it should work that way (it seems fine to me; every element of the sequence conforms to the predicate) but the very first thing to check before you ask whether something is a bug, is the documentation. (It's the first thing to check as soon as a method behaves in a way other than what you expected.)
All requires the predicate to be true for all elements of the sequence. This is explicitly stated in the documentation. It's also the only thing that makes sense if you think of All as being like a logical "and" between the predicate's results for each element. The true you're getting out for the empty sequence is the identity element of the "and" operation. Likewise, the false you get from Any for the empty sequence is the identity for logical "or".
If you think of All as "there are no elements in the sequence that are not", this might make more sense.
It is true, as nothing (no condition) makes it false.
The docs probably explain it. (Jon Skeet also mentioned something a few years back)
Same goes for Any (the opposite of All) returning false for empty sets.
Edit:
You can imagine All to be implemented semantically the same as:
foreach (var e in elems)
{
if (!cond(e))
return false;
}
return true; // no escape from loop
Most answers here seem to go along the lines of "because that's how is defined". But there is also a logical reason why is defined this way.
When defining a function, you want your function to be as general as possible, such that it can be applied to the largest possible number of cases. Say, for instance, that I want to define the Sum function, which returns the sum of all the numbers in a list. What should it return when the list is empty? If you'd return an arbitrary number x, you'd define the function as the:
Function that returns the sum of all numbers in the given list, or x if the list is empty.
But if x is zero, you can also define it as the
Function that returns x plus the given numbers.
Note that definition 2 implies definition 1, but 1 does not imply 2 when x is not zero, which by itself is enough reason to pick 2 over 1. But also note 2 is more elegant and, in its own right, more general than 1. Is like placing a spotlight farther away so that it lightens a larger area. A lot larger actually. I'm not a mathematician myself but I'm sure they'll find a ton of connections between definition 2 and other mathematical concepts, but not so many related to definition 1 when x is not zero.
In general, you can, and most likely want to return the identity element (the one that leaves the other operand unchanged) whenever you have a function that applies a binary operator over a set of elements and the set is empty. This is the same reason a Product function will return 1 when the list is empty (note that you could just replace "x plus" with "one times" in definition 2). And is the same reason All (which can be thought of as the repeated application of the logical AND operator) will return true when the list is empty (p && true is equivalent to p), and the same reason Any (the OR operator) will return false.
The method cycles through all elements until it finds one that does not satisfy the condition, or finds none that fail. If none fail, true is returned.
So, if there are no elements, true is returned (since there were none that failed)
Here is an extension that can do what OP wanted to do:
static bool All<T>(this IEnumerable<T> source, Func<T, bool> predicate, bool mustExist)
{
foreach (var e in source)
{
if (!predicate(e))
return false;
mustExist = false;
}
return !mustExist;
}
...and as others have pointed out already this is not a bug but well-documented intended behavior.
An alternative solution if one does not wish to write a new extension is:
strs.DefaultIfEmpty().All(str => str == "ABC");
PS: The above does not work if looking for the default value itself!
(Which for strings would be null.)
In such cases it becomes less elegant with something similar to:
strs.DefaultIfEmpty(string.Empty).All(str => str == null);
If you can enumerate more than once the easiest solution is:
strs.All(predicate) && strs.Any();
i.e simply add a check after that there actually were any element.
Keeping the implementation aside. Does it really matter if it is true? See if you have some code which iterates over the enumerable and executes some code. if All() is true then that code is still not going to run since the enumerable doesn't have any elements in it.
var hungryDogs = Enumerable.Empty<Dog>();
bool allAreHungry = hungryDogs.All(d=>d.Hungry);
if (allAreHungry)
foreach (Dog dog in hungryDogs)
dog.Feed(biscuits); <--- this line will not run anyway.
In my code I have an arraylist, called heart, which contains numbers from 1-13.
heart.Add("any");
for(int i = 0; i < 14; i++)
{
heart.Add(i);
}
As you can see it also contains "any" placed in the first element. When I use this code to get the all of the elements that has a value over 5 I get an error.
int store = heart.Cast<int>().Where(item => item > 5).Count().ToString();
I get the error "Specified cast is not valid" and that's because of the
"any" I have in the first element. Could anyone help me fix this?
It sounds like you just need the OfType method instead:
string store = heart.OfType<int>().Where(item => item > 5).Count().ToString();
OfType only returns values which are of the approriate type, ignoring others. See my Edulinq blog post on it for more information.
As Sven shows, you can also use the overload of Count which takes a predicate, to remove the Where call:
string store = heart.OfType<int>().Count(item => item > 5).ToString();
(I've changed the variable type given that you're calling ToString at the end... again, you may want to think about this decision. It depends on how you're using it of course.)
However, I'd strongly advise you to use a strongly-typed collection instead of ArrayList. Think about what the collection is meant to hold - it seems odd to hold both strings and integers. What are you trying to do with it?
Use this instead:
int count = heart.OfType<int>().Count(item => item > 5);
OfType will filter the list and return only those elements that are the correct type, rather than Cast which tries to cast all elements.
You can't cast the word "any" to an integer, that's pretty straight forward.
We'd have to know exactly what your trying to do with here, and how the array is used to really give a good recommendation.
Since you're using int and you wanted values of 1-13, may I suggest you use an int value of 0 to represent 'any'?
You could do
Int store = heart.GetRange(1, heart.Count - 1).Cast<int>().Where(item => item > 5).Count().ToString();