3

Suppose I have a string array and it may contain some data which can be parsed into an integer.

string[] strnums = { "2", "3", "hello", "5", "6", "8" };

I am trying to convert this string array into an integer array using LINQ Select method, something like this:-

int[] numbers = strnums.Select(x =>
                {
                    int temp = 0;
                    return int.TryParse(x, out temp) ? temp : 0;
                }).ToArray();

Output: 2,3,0,5,6,8 //Don't want 0 here

Here, in the else block of int.TryParse I had to give a default value (0), but I don't need this, that's why I titled my question as "By-Pass" the else part.

I have then used this query, and this is working fine, means it is not inserting unnecessary zero if string is not parsed:-

int[] numbers1 = strnums.Select(x => 
                {
                    int temp = 0;
                    bool isParsed = int.TryParse(x, out temp);
                    return new { temp, isParsed };
                })
                .Where(x => x.isParsed)
                .Select(x => x.temp)
                .ToArray();

But, this seems to be a lot of code, just for the sake of not considering the default value, I am projecting, filtering and again projecting. Is this the right approach?

2
  • I think it makes sense in general, since Linq treats between projecting and filtering as separate, sequential operations. I tend to use a nullable int for this, but your mileage may vary. Commented Dec 31, 2014 at 10:36
  • 2
    I don't see any problem with the second example. It makes sense and actually explicitly describes what you want instead of being "clever". Commented Dec 31, 2014 at 10:38

5 Answers 5

5

Why not implement in good old fashion - at least its easily understandable

        var nums = new List<int>();
        var numStrings = new List<string>{ "1", "2", "hello" };
        numStrings.ForEach(numString =>
        {
            int temp;
            if (int.TryParse(numString, out temp))
                nums.Add(temp);
        });

You can save some tiger balm!!!

Sign up to request clarification or add additional context in comments.

Comments

4

I will say that your second example is more than adequate solution to your problem.

Unlike other answers, it actually makes it explicit that you only want values that can be parsed. All other solutions, while being clever, obfuscate this fact. The main reason why I found the second example a better solution is isParsed field, especially when coupled with .Where(x => x.isParsed). This is what makes it obvious that you want only values that were successfully parsed. Anyone who reads the code for the first time will immediately think "only get values that were parsed". Also, there is no ambiguity in the code.

Also, I would disagree that second example is bad, because it is longer. You should focus more on how self-describing the code is and not which is shorter. This is one of the wrong ideas that new developers get. They think, that they are better developers if they can produce code that is shorter, that they are better developers. And while code-golf is interesting discipline, most people don't want to see such code in production environment.

5 Comments

Er... The two other answers (the ones not deleted, anyway), by Lee and by dbc, both seem clear to me about the intent of the code. What do you find unclear about them?
@hvd But they are not clear about intent of the programmer. dbc'd is pretty much same as in question and Lee's would need a minute trying to figure out what is happening without knowing the problem beforehand.
I was trying to ask not whether you find Lee's answer more difficult to understand, but what about it makes it more difficult to understand for you. I'm asking because I just don't see it, it seems perfectly clear to me.
@hvd First, see my edit. Second, Lee's answer is using SelectMany, which I found to be much less understood among less experienced developers. Also, it is using one-value array and empty array to represent what the OP's example uses anonymous and properly named class.
On the other hand, using arrays of lengths zero and one avoids the returning a value to represent the fact that you don't have any value to return, which is seen as an anti-pattern by some (not necessarily by me). Lee's approach uses an anonymous function that returns zero ints to represent the fact that no ints could be obtained from the string, and returns one int to represent the fact that one int could be obtained from the string. It's probably not worth getting into a big discussion over, but I hope you can agree that while your point of view is valid, it's not the only valid one.
2

You could use SelectMany:

int[] ints = strnums.SelectMany(s =>
            {
                int i;
                return int.TryParse(s, out i) ? new[] { i } : new int[0];
            }).ToArray();

Comments

2

I think your code looks good, and is readable. You might consider using a nullable int for the failed parsing result, then filtering it out:

    int[] numbers = strnums.Select(x =>
    {
        int temp = 0;
        return int.TryParse(x, out temp) ? (int?)temp : (int?)null;
    })
    .Where(i => i != null)
    .Select(i => i.Value)
    .ToArray();

Using a null value for a nullable is a conventional, built-in way to represent a missing value. Also, in very tight loops, this avoids the memory pressure of allocating the anonymous class.

3 Comments

This is what I would do, except I might extract the selector into a reusable function. It's effectively the same approach as the question though: Nullable<T> is pretty much the question's anonymous class, with isParsed renamed to HasValue, and temp renamed to Value.
@hvd - true, I think the approach in the question is good. But for iterating over something very small like an integer, this avoids the memory pressure of allocating the anonymous type for each iteration. I've been bitten by this before so I tend to avoid it.
Sure, that generally will be insignificant, but can make a measurable difference in tight loops. But like I said, this is what I would do, I'm not saying you should change that part. :) Personally, if a built-in type suits my needs just as well as a user-defined type, that's enough of a reason for me to go for the built-in type. Readability could be a reason why a built-in type might be a worse match, but null is well-established as the value to represent "we don't have any int value", so it looks good to me.
-1
int re;

List<Installer> installers_list = db.Installers.ToList().Where(a => 
int.TryParse(a.Install_Date, out re) == true && int.Parse(a.Install_Date) >= StartDate && 
int.Parse(a.Install_Date) <= EndDate).ToList();

//This worked for me

1 Comment

While this might answer the question, you should edit your answer to include proper code formatting, as well as an explanation of how this code block answers the question. This helps to make your code more readable and provides context, which makes your answer much more useful for future readers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.