6
\$\begingroup\$

I wrote the following function to determine whether a string ends with one of a few given options.

I'm sure it can be written more elegantly, probably avoiding the loop.

bool EndsWithOneOf(string value, IEnumerable<string> suffixes)
{ 
 foreach(var suffix in suffixes)
 {
 if value.EndsWith(suffix)
 return true;
 }
 return false;
}
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Aug 18, 2011 at 17:43
\$\endgroup\$
5
  • \$\begingroup\$ My previous answer was given multiple times, but this works too. Using a method group: bool EndsWithOneOf(string value, IEnumerable<string> suffixes) { return suffixes.Any(value.EndsWith); } \$\endgroup\$ Commented Aug 18, 2011 at 17:48
  • \$\begingroup\$ @Abbas You can edit your current answer to include that if you like. No need to demote it to a comment! \$\endgroup\$ Commented Aug 18, 2011 at 17:50
  • \$\begingroup\$ Ok thanks, didn't know that! :) I put it in my previous answer. \$\endgroup\$ Commented Aug 18, 2011 at 17:52
  • 1
    \$\begingroup\$ You can't enumerate without... you know, enumerating. Any implementation will involve a loop, and there's nothing wrong with that. That's what loops are for... no pun intended =) \$\endgroup\$ Commented Aug 19, 2011 at 0:06
  • \$\begingroup\$ Could also try some regex options depending on your use case \$\endgroup\$ Commented Sep 28, 2018 at 1:54

5 Answers 5

17
\$\begingroup\$

You can LINQify it to improve readability:

bool endsWithOneOf = suffixes.Any(x => value.EndsWith(x));

Note that this doesn't "avoid the loop", since Any() will iterate through the suffixes (stopping when it hits a match.) But that's ok, since how else could you do it? You have an enumeration of suffixes, so to do anything with them, you must enumerate them.

answered Aug 18, 2011 at 17:44
\$\endgroup\$
6
  • \$\begingroup\$ No prob! In general, if you have a foreach loop, you should try to "Think LINQ". \$\endgroup\$ Commented Aug 18, 2011 at 17:50
  • \$\begingroup\$ @dlev - I guess that would depend on how legible the code looks after you LINQ-ify it. Sometimes you sacrifice readability in those instances, which makes maintaining (probably by other developers) a little more challengeing (well, it becomes an obstacle...just a small one). \$\endgroup\$ Commented Aug 18, 2011 at 17:58
  • \$\begingroup\$ @Matthew That's a good point. Personally, I've found that LINQ very often makes my code more readable, but there are certainly cases where that's not true. \$\endgroup\$ Commented Aug 18, 2011 at 17:59
  • \$\begingroup\$ @dlev - I agree, I use it all over the place. I have encountered issues where other team members have initial struggled to understand what it is doing, but once they get the syntax, LINQ becomes second nature. In this case, with suffixes.Any(...) it is quite clear what the method is doing, moreso than the foreach variant. \$\endgroup\$ Commented Aug 18, 2011 at 18:03
  • 2
    \$\begingroup\$ @Matthew: You should not have to don't dumb down your code just because a few people do not understand the syntax or the libraries. It's their responsibility to keep up it and using LINQ as a part of a .NET 3.5+ application has become the norm. This reminds me of this recent discussion on Software Engineering. \$\endgroup\$ Commented Aug 18, 2011 at 22:29
12
\$\begingroup\$
bool EndsWithOneOf(string value, IEnumerable<string> suffixes)
{
 return suffixes.Any(suffix => value.EndsWith(suffix));
}

Edit: too late :D

Update

My previous answer was given multiple times, but this works too. Using a method group:

bool EndsWithOneOf(string value, IEnumerable<string> suffixes)
{
 return suffixes.Any(value.EndsWith);
}
answered Aug 18, 2011 at 17:45
\$\endgroup\$
0
5
\$\begingroup\$
static bool EndsWithOneOf(this string value, IEnumerable<string> suffixes)
{
 return suffixes.Any(suffix => value.EndsWith(suffix));
}

Two advantages here:

  1. use of extension method makes calling this method more straight forward (i.e. mystring.EndsWithOneOf(mySuffixes);)
  2. Use of linq allows for better readability (see declarative vs imperative programming)
answered Aug 18, 2011 at 17:48
\$\endgroup\$
0
4
\$\begingroup\$

Regardless of how you do it, at some point in the execution of a method like that, there will be a enumeration.

What you can do, is make the method more terse by using a LINQ method:

return suffixes.Any(s => value.EndsWith(s));

But is that any more readable than:

foreach (string suffix in suffixes) {
 if (value.EndsWith(suffix)) return true;
}
return false;

For actual method improvements, you should consider argument validation. What happens if value is null? Your current code will return in a NullReferenceException.

Behaviourly would it be correct to throw an ArgumentNullException in this case? Or is the possible null value an automatic resultant value of false?

You should also consider how your are comparing strings? Should you provide an overload that allows the caller to pass in an appropriate CultureInfo object? Or perhaps specify the StringComparison?

answered Aug 18, 2011 at 17:49
\$\endgroup\$
2
\$\begingroup\$

I don't think this is relevant given your question example, and therefore this answer may be pointless, but an alternative is that you can invert the comparison test to eliminate the enumeration.

For example, if you were looking for file type extensions, then instead of comparing the filename against a collection of extensions (like has been solved already), you can build a single string containing all the extensions (plus maybe an extra token), and then search for the input filename type in that string.

E.g.

".png.jpg.bmp.mov.mp3.".contains(myFileExtension + ".");

I've used this approach a few times to unravel a loop.

Sᴀᴍ Onᴇᴌᴀ
29.5k16 gold badges45 silver badges201 bronze badges
answered Aug 23, 2011 at 18:07
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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