Lambda expression to return zero if null

in my WPF application i used to add controls dynamically to a Canvas. The name format of the control is "Control_UniqueValue".

i.e., if i add first control to the canvas, then the name will be "Control_1" and the next will be "Control_2" etc...

my requirement is to get the max value of the added controls

i used the following statement for that

string maxId = (string)canvas1.Children.Cast<FrameworkElement>().ToList().Max(x => (x.Name.Substring(x.Name.LastIndexOf('_') + 1)));

but the problem here is

  1. need to return the value as int

  2. if the canvas contains no controls it will raise error (tried using Nullable type, but failed)

Answers


int  maxId = canvas1.Children
    .Cast<FrameworkElement>()
    .Select(e => int.Parse(e.Name.Substring(e.Name.LastIndexOf('_'))))
    .DefaultIfEmpty()
    .Max();

This should return 0 instead of throwing an exception if there are no elements in the sequence. Also, the call to ToList in your code is not required. This will still throw an exception if any of the control names are not in the expected format.


To get an integer, you might use the int.Parse method. You don't have to call ToList().

There is no error checking, so your controls have to named regarding to your rule name_id.

You can use the DefaultIfEmpty extension method to provide a default value, if the sequence is empty:

int maxId = canvas1.Children
             .Cast<FrameworkElement>()
             .DefaultIfEmpty(new FrameworkElement() { Name = "Control_0" })
             .Max(x => (int.Parse(x.Name.Split('_')[1]) + 1)));

Since Max() requires at least one element in its sequence you either have to

  • catch the exception and set max to zero
  • check the length before calling Max(). I'd recommend this

While it is possible to write the logic in one long query expression, I'd recommend you break it up a bit to improve readability. Create a method that returns the integer part of a child control's name:

private int NumberFromElementName(string name)
{
    // Or search for the last '_' using name.LastIndexOf()
    var numString = name.Substring("Control_".Length);
    return Int32.Parse(numString);
}

Then do the query in two steps to allow you to look at the length of the returned sequence. Notice I convert it to an array to avoid having to run the query twice. I'm also using the OfType extension method so that it works even if the canvas has a child which isn't of type FrameworkElement.

var children = canvas1.Children.OfType<FrameworkElement>().ToArray();
int max = 0;
if (children.Length > 0)
    max = children.Max(x => NumberFromElementName(x.Name));
string nextChildName = String.Format ("Control_{0}", max + 1);

EDIT: As pointed out by @Jan in his answer, you can avoid splitting the query in two parts by using the DefaultIfEmpty before the Max call in the query.


got the final answer

int maxId = canvas1.Children .Cast<FrameworkElement>() .Select(e => int.Parse(e.Name.Substring(e.Name.LastIndexOf('_')+ 1))) .DefaultIfEmpty() .Max(x => x + 1); 

Thanks Jan & Lee


Need Your Help

Is there any way to draw the Concave Polygon in Box2D and detect the collision with other shapes

ios polygon box2d-iphone physics-engine

I am beginner in Box2D physics engine. As I am having a Image with irregular curves I am trying to develop the polygon. But with the reference of the Raywenderlich demo tutorial using the Vertex He...

ruby on rails use variable in association call

ruby-on-rails variables view associations render

i have a helper function which renders a partial and i pass a variable called method with it into the view...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.