简体   繁体   中英

can I do something like a foreachwhile loop(that's how I will be refering to it) in c#?

I have looked into this some, and I can't find a good way to do this. I have functional code but I want to clean it up without using manual counting or breaks. I looked at LINQs TakeWhile function, but that is insufficient in this case. Here is an example of a working implementation of a functional equivalent:

bool foo(List<strings> stringList, int counter)//assume this list has, like, 10 elements, and counter=3, idk
{
    ...

    bool found= false;
    for(int i=0; i<stringList.Count && !found; i++)
    {
        if(stringlist[i].length < 2 || counter >=6)
            found=true;
        counter++;
    }

    ...

    return found
}

And I want to replace it with some "magic" function like this:

bool foo(List<strings> stringList, int counter)//assume this list has, like, 10 elements, and counter=3, idk
{
    ...

    bool found= false;
    foreachwhile(string s in stringList while !found)
    {
        if(s.length < 2 || counter >=6)
            found=true;
        counter++;
    }

    ...

    return found
}

Is there some function that can do this already, and if not how can I write one in C#... or get close? I often find I need to do this, and yes, I know that:

bool foo(List<strings> stringList, int counter)//assume this list has, like, 10 elements, and counter=3, idk
{
    ...

    bool found= false;
    foreach(string s in stringList)
    {
        if(found)
            break;
        if(s.length < 2 || counter >=6)
            found=true;
        counter++;
    }

    ...

    return found
}

technically works too, but I would like to avoid breaks in my code. Is there any other clean way to accomplish this in c#?

EDIT: I am seeing a lot of confusion about what I am asking here. I would prefer a way to add a very clear check if we should break to the foreach statement itself if possible, or a way to write my own version of foreach that accepts a parameter that only continues while a condition is true, such as the path isn't found yet.

Also, I am sorry for not being clear, but the biggest reason I want to avoid break is so that I am not jumping out of the loop at an arbitrary point. In this respect return is just as undesirable.

I also have nothing against Linq, I tried to use it, but I found it does not produce the functionality that I am looking for:

bool foo(List<strings> stringList, int counter)//assume this list has, like, 10 elements, and counter=3, idk
{
    bool found= false;
    foreach(string s in stringlist.Takewhile(x=> (!found)))
    {
        if(s.length < 2 || counter >=6)
            found=true;
        counter++;
    }
    return found
}

is different logic from the above because TakeWhile executes first and returns an empty set causing the foreach loop to have nothing to loop over. If someone has another way to write this, I would genuinely love to hear it as syntactically it looks extremely clean.

The fact that there is other code before and after the loop indicates that you should Refactor your code to separate the concerns. Your code will improve if you separate pieces of logic into different places. Long methods with closely-coupled logic is not reusable and is hard to maintain.

For example your method could return the logical combination of several different pieces of logic, each of which is delegated to a different method. The piece of logic which is shown could be delegated to another method as follows.

I would use break , since it is designed to do exactly what you want, and there is nothing wrong with it. But for your specific example, you could also avoid break like this...

bool foo_part2(List<strings> stringList, int counter)
{
    foreach (string s in stringList)
    {
        if(s.length < 2 || counter >=6)
            return true;
        counter++;
    }
    return false;
}

...And the original method would look something like this..

bool foo(List<strings> stringList, int counter)
{
    return foo_part1(stringList,counter) ||
        foo_part2(stringList,counter) ||
        foo_part3(stringList,counter);
}

(You may need to use && s instead of || , depending on the required logic.) With properly named methods (rather than this "foo" example), this can be very easy to read, and will avoid you having to look into the function to see what it's doing.

However, to conclude... there is a mistake in the question. You state "I also have nothing against Linq, I tried to use it, but I found it does not produce the functionality that I am looking for... because TakeWhile executes first" . That isn't correct. Which means that you didn't try it yourself, and that you didn't understand the answer you were given to your previous question 20 minutes before asking this one . It is using a predicate, so the value is evaluated each time through the iteration, which is exactly what you want. So this entire question is flawed, and if you had just tried it yourself (before even asking your previous question), you would have worked that out yourself.

I refer the OP to the question of How much research effort is expected of Stack Overflow users? .

Not sure what your code is doing; but following achieves the same thing using Linq Any.

bool foo(List<string> stringList, int counter)//assume this list has, like, 10 elements, and counter=3, idk
            {
                return stringList.Any(s =>
                {
                    var found = s.Length < 2 || counter >= 6;
                    counter++;
                    return found;
                });            
            }

If you insist to don't use break the alternative way is to use delegates, although using break is best practice.

...

bool found= false;
Action Search = () =>
{
    foreach(string s in stringList)
    {
        if(s.length < 2 || counter >=6)
            found=true;
            return;
        counter++;
    }
}

Search();

...

Don't use this code. Use break.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM