Suppose you wanna test or compare the equality of two Vectors.
Suppose you have:
string[] models = {"ModelOne", "ModelTwo", "ModeThree"};
And another one that you don't know for sure what will be inside of it, but you believe that it will contain the same elements like models owner above.
I have this method to make this verification and I use it in a Unit test passing the vector models presented above.
public bool TemplateForDependenciesTests (string[] v)
{
var dependency = new Dependencies();
var result = dependency.GetByReferencedModel(typeof(T).ToString());
//foreach (var i in result)
//{
//if ((v.Any(model => model == i.ReferencingModelName)))
//return false;
//}
return result.Any(x => (v.Any(model => model == x.ReferencingModelName)));
}
the result variable will hold the return of this method:
public IEnumerable<Dependency> GetByReferencedModel(string referencedModelName)
{
return this.dependencies
.Where(d => d.ReferencedModelName == referencedModelName);
}
The question is: How can I make that return statement in TemplateForDependenciesTests() work nicely and in a way I can snoop that indeed it is doing what I expect, because till now I moved some stones here and there, but it appears not doing what I want?
It looks like you're just trying to see if any member of result has a ReferencingModelName that's in the models collection. Seems like this would do it:
return result.Select(x => x.ReferencingModelName).Intersect(v).Any();
Now, if you want to snoop to see if it's really doing what you expect:
var intersection = result.Select(x => x.ReferencingModelName).Intersect(v).ToList();
// now you can examine the contents of the intersection list
// and you can return the result
return intersection.Any();
You might even go one step further:
var result = dependency.GetByReferencedModel(typeof(T).ToString()).ToList();
var names = result.Select(x => x.ReferencingModelName).ToList();
var intersection = names.Intersect(v).ToList();
return intersection.Any();
With that, you can examine the results of each step, and you should be able to see where the error exists.
Order doesn't matter to Intersect. That is if you have:
var x = new string["a", "b", "c"];
var y = new string["c", "b"];
var z = new string["b", "c"];
Then x.Intersect(y) == y.Intersect(x) == x.Intersect(z) == y.Intersect(z), etc.
You could make your lambdas easier to debug by making them multi-line statements. E.g. you could put breakpoints all over this to see exactly what's happening.
var resultList = result.ToList();
return resultList.Any(x =>
{
bool outer = v.Any(model =>
{
bool inner = model == x.ReferencingModelName;
return inner;
});
return outer;
});
I'll also note that with things like ToLookup or ToDictionary, and HashSet<T>, you could make all of these lookups much faster and more intuitively-coded.
Related
Let's suppose I receive a collection of strings from user. I need to convert them to GUID sequences for further processing. There is a chance, that user may enter invalid data (not correct GUID sequence), so I need to validate input. Additionally, I can run business-process if only all uploaded data are correct GUID values. Here is my code:
IEnumerable<string> userUploadedValues = /* some logic */;
bool canParseUserInputToGuid = userUploadedValues.All(p => Guid.TryParse(p, out var x));
if(canParseUserInputToGuid)
var parsedUserInput = userUploadedValues.Select(p=> Guid.Parse(p));
This logic works pretty well, but I don't like it as actually I am doing work twice. In second line, Guid.TryParse(p, out var x) already writing parsed GUID sequence to the X variable. Is there an approach to combine validating and mapping logic - if sequence elements satisfy for condition (All) then map this elements to a new collection (Select) in one query? It is important for me also in terms of performance, as it is possible that client will send large amount of data (1, 000, 000+ elements) and doing twice work here is a bit inefficient.
You can do something like this in one Select:
var parsedUserInput = userUploadedValues.Select(p => Guid.TryParse(p, out var x) ? x : default)
.Where(p => p != default);
For this one, you need to be sure if there is no Guid.Empty input from the user.
Otherwise, you can return a nullable Guid if parsing doesn't succeed:
var parsedUserInput = userUploadedValues.Select(p => Guid.TryParse(p, out var x) ? x : default(Guid?))
.Where(p => p != null);
Another solution by creating an extension method, for example:
public static class MyExtensions
{
public static Guid? ToGuid(this string arg)
{
Guid? result = null;
if(Guid.TryParse(arg, out Guid guid))
result = guid;
return result;
}
}
and usage:
var parsedUserInput2 = userUploadedValues.Select(p => p.ToGuid())
.Where(p => p != null);
But keep in mind that in this cases, you will have a collection of nullable Guids.
Your out var x variable will be Guid.Empty in the case where it is not a valid Guid. So you can just do this:
IEnumerable<string> userUploadedValues = new[]
{
"guids.."
};
var maybeGuids = userUploadedValues.Select( x => {
Guid.TryParse( x, out var #guid );
return #guid;
} );
if ( maybeGuids.All( x => x != Guid.Empty ) )
{
//all the maybe guids are guids
}
You can optimize the validation and conversion like below,
IEnumerable<string> userUploadedValues = /* some logic */;
var parsedGuids = userUploadedValues.Where(p => Guid.TryParse(p, out var x));
if(userUploadedValues.Count() != parsedGuids.Count())
{
//Some conversion failed,
}
If the count of both the lists same, then you have all the converted GUIDs in the parsedGuids.
Sometimes the non-LINQ method is just easier to read and no longer.
var parsedUserInput = new List<string>();
foreach(var value in userUploadedValues)
{
if (Guid.TryParse(value, out var x)) parsedUserInput.Add(x);
else...
}
I have the following 2 lines,
var productStrucutre = _service.GetProductStructureWithParent(partId).ToList(); // returns a list of objects
var product = productStrucutre.Find(_ => _.Part == part); // Returns a part
if the following condition fails because the part does not exist, then i would like to return the whole product structure.
var product = productStrucutre.Find(_ => _.Part == part);
So the find will fall away
I assume you mean something like this:
var productStructure = _service.GetProductStructureWithParent(partId).ToList();
var product = productStrucutre.Where(x => x.Part == part);
return product.Any() ?
product : // return only those products that fit the condition
productStructure; // return all objects
I have a query something like this
function List<CustomObject2> GetDataPoint(List<CustomObject> listDataPoints)
{
if(listDataPoints.Count == 0)
return;
var startPoint = new CustomObject();
startPoint = listDataPoint.First();
List<CustomObject2> cObjList = from r in listDataPoints
where r != null && r.GetDistance(startPoint) > 100
select new CustomObject2
{
Var1 = r.Var1
}.ToList()
}
The problem here is that, in the beginning the startPoint is set to the first object in listDataPoint. However, after the comparison in the query (GetDistance) I want to reassign startPoint to the value of "r" if the Distance is greater than 100.
Is there any way to do so?
Thanks in advance
No, there is no clean way to do that.
LINQ is essentially a piece of functional programming that has been brought into C#. In functional programming values are immutable (they cannot be changed). Thanks to being functional and using immutality, LINQ queries can be lazily evaluated. It is not uncommon for a LINQ query to be only partly run, or for some parts of the sequence to be evaluated several times. That is safe to do thanks to immutability.
As soon as you want to change a value, you are working against LINQ. In this case you are much better off with a for loop.
Of course there are ways to solve this in a functional manner, as it is possible to solve this in a purely functional language. But in C# it is much cleaner to use a for loop.
You can use a fold:
var cObjList = listDataPoints.Where(r => r != null)
.Aggregate(Tuple.Create(startPoint, new List<CustomObject2>()), (acc, r) => {
if(r.GetDistance(acc.Item1)) {
acc.Item2.Add(new CustomObject2 { Var1 = r.Var1 });
return Tuple.Create(r, acc.Item2);
}
else return acc;
}).Item2;
Since you were not-null checking the elements from listDataPoints, so I assume it may contain null objects. In this case, your code may be vulnerable when the First() element from the list is empty.
//there is no function or procedure in c#;
//function List<CustomObject2> GetDataPoint(List<CustomObject> listDataPoints)
List<CustomObject2> GetDataPoint(List<CustomObject> listDataPoints)
{
var dataPoints = listDataPoints.Where(r => r != null);
if (dataPoints.Empty())
//return; you cant not return anything in a function
return null; //or return an empty list
//return new List<CustomObject2>();
var cObjList = dataPoints.Aggregate(
new Stack<CustomObject>(),
(results, r) =>
{
if (r.GetDistance(results.Peek()) > 100)
results.Add(r);
return results;
})
.Select(r => new CustomObject2(){ Var1 = r.Var1 })
.ToList();
//return directly the line above or do more work with cObjList...
}
Yet, this is still messy and not easily maintained. Like Anders Abel suggests, you are best to go with the for loop for this case :
var cObjList= new List<CustomObject2>();
foreach(var r in dataPoints)
{
if (r.GetDistance(results.Peek()) > 100)
results.Add(new CustomObject2(){ Var1 = r.Var1 });
}
//...
return cObjList;
Here is some sample code I have basically written thousands of times in my life:
// find bestest thingy
Thing bestThing;
float bestGoodness = FLOAT_MIN;
foreach( Thing x in arrayOfThings )
{
float goodness = somefunction( x.property, localvariable );
if( goodness > bestGoodness )
{
bestGoodness = goodness;
bestThing = x;
}
}
return bestThing;
And it seems to me C# should already have something that does this in just a line. Something like:
return arrayOfThings.Max( delegate(x)
{ return somefunction( x.property, localvariable ); });
But that doesn't return the thing (or an index to the thing, which would be fine), that returns the goodness-of-fit value.
So maybe something like:
var sortedByGoodness = from x in arrayOfThings
orderby somefunction( x.property, localvariable ) ascending
select x;
return x.first;
But that's doing a whole sort of the entire array and could be too slow.
Does this exist?
This is what you can do using System.Linq:
var value = arrayOfThings
.OrderByDescending(x => somefunction(x.property, localvariable))
.First();
If the array can be empty, use .FirstOrDefault(); to avoid exceptions.
You really don't know how this is implemented internally, so you can't assure this will sort the whole array to get the first element. For example, if it was linq to sql, the server would receive a query including the sort and the condition. It wouldn't get the array, then sort it, then get the first element.
In fact, until you don't call First, the first part of the query isn't evaluated. I mean this isn't a two steps evaluation, but a one step evaluation.
var sortedValues =arrayOfThings
.OrderByDescending(x => somefunction(x.property, localvariable));
// values isn't still evaluated
var value = sortedvalues.First();
// the whole expression is evaluated at this point.
I don't think this is possible in standard LINQ without sorting the enuermable (which is slow in the general case), but you can use the MaxBy() method from the MoreLinq library to achieve this. I always include this library in my projects as it is so useful.
http://code.google.com/p/morelinq/source/browse/trunk/MoreLinq/MaxBy.cs
(The code actually looks very similar to what you have, but generalized.)
I would implement IComparable<Thing> and just use arrayOfThings.Max().
Example here:
http://msdn.microsoft.com/en-us/library/bb347632.aspx
I think this is the cleanest approach and IComparable may be of use in other places.
UPDATE
There is also an overloaded Max method that takes a projection function, so you can provide different logic for obtaining height, age, etc.
http://msdn.microsoft.com/en-us/library/bb534962.aspx
I followed the link Porges listed in the comment, How to use LINQ to select object with minimum or maximum property value and ran the following code in LINQPad and verified that both LINQ expressions returned the correct answers.
void Main()
{
var things = new Thing [] {
new Thing { Value = 100 },
new Thing { Value = 22 },
new Thing { Value = 10 },
new Thing { Value = 303 },
new Thing { Value = 223}
};
var query1 = (from t in things
orderby GetGoodness(t) descending
select t).First();
var query2 = things.Aggregate((curMax, x) =>
(curMax == null || (GetGoodness(x) > GetGoodness(curMax)) ? x : curMax));
}
int GetGoodness(Thing thing)
{
return thing.Value * 2;
}
public class Thing
{
public int Value {get; set;}
}
Result from LinqPad
NOTE: Right before posting this question it occurred to me there's a better way of doing what I was trying to accomplish (and I feel pretty stupid about it):
IEnumerable<string> checkedItems = ProductTypesList.CheckedItems.Cast<string>();
filter = p => checkedItems.Contains(p.ProductType);
So OK, yes, I already realize this. However, I'm posting the question anyway, because I still don't quite get why what I was (stupidly) trying to do wasn't working.
I thought this would be extremely easy. Turns out it is giving me quite a headache.
The basic idea: display all the items whose ProductType property value is checked in a CheckedListBox.
The implementation:
private Func<Product, bool> GetProductTypeFilter() {
// if nothing is checked, display nothing
Func<Product, bool> filter = p => false;
foreach (string pt in ProductTypesList.CheckedItems.Cast<string>()) {
Func<Product, bool> prevFilter = filter;
filter = p => (prevFilter(p) || p.ProductType == pt);
}
return filter;
}
However, say the items "Equity" and "ETF" are both checked in ProductTypesList (a CheckedListBox). Then for some reason, the following code only returns products of type "ETF":
var filter = GetProductTypeFilter();
IEnumerable<Product> filteredProducts = allProducts.Where(filter);
I guessed it might have had something to do with some self-referencing messiness where filter is set to, essentially, itself or something else. And I thought that maybe using ...
filter = new Func<Product, bool>(p => (prevFilter(p) || p.ProductType == pt));
...would do the trick, but no such luck. Can anybody see what I am missing here?
I believe you have a modified closure problem here. The pt parameter is bound into the lambda expression but changes as the loop progresses. It's important to realize the when a variable is referenced in a lambda it is the variable that is captured, not the value of the variable.
In loops this has a very significant ramification - because the loop variable is changing, not being redefined. By creating a variable inside the loop, you are creating a new variable for each iteration - which then alows the lambda to capture each independently.
The desired implementation would be:
foreach (string pt in ProductTypesList.CheckedItems.Cast<string>()) {
string ptCheck = pt;
Func<Product, bool> prevFilter = filter;
filter = p => (prevFilter(p) || p.ProductType == ptCheck);
}
Eric Lippert has written about this specific situation:
http://blogs.msdn.com/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx
http://blogs.msdn.com/ericlippert/archive/2009/11/16/closing-over-the-loop-variable-part-two.aspx
Also, see the question Access to Modified Closure (2) for a good explanation of what happens with closure variables. There's also an series of articles on the blog The Old New Thing that has an interesting perspective on this:
http://blogs.msdn.com/oldnewthing/archive/2006/08/02/686456.aspx
http://blogs.msdn.com/oldnewthing/archive/2006/08/03/687529.aspx
http://blogs.msdn.com/oldnewthing/archive/2006/08/04/688527.aspx
It has to do with closures. The variable pt will always refer to the last value of the for loop.
Consider the following example where the output is the one expected because it's using a variable that is scoped inside the for loop.
public static void Main(string[] args)
{
var countries = new List<string>() { "pt", "en", "sp" };
var filter = GetFilter();
Console.WriteLine(String.Join(", ", countries.Where(filter).ToArray()));
}
private static Func<string, bool> GetFilter()
{
Func<string, bool> filter = p => false;
foreach (string pt in new string[] { "pt", "en" })
{
Func<string, bool> prevFilter = filter;
string name = pt;
filter = p => (prevFilter(p) || p == name);
}
return filter;
}
Since you're looping and setting the filter type to itself, you're setting the product type to the last pt in each case. It's a modified closure and since it's delay bound, you need to copy it on each loop, like this:
foreach (string pt in ProductTypesList.CheckedItems.Cast<string>()) {
var mypt = pt;
Func<Product, bool> prevFilter = filter;
filter = p => (prevFilter(p) || p.ProductType == mypt);
}
This should result in the right result, otherwise the last pt is used for all equality checks.