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;
}
-
\$\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\$Abbas– Abbas2011年08月18日 17:48:30 +00:00Commented 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\$dlev– dlev2011年08月18日 17:50:13 +00:00Commented Aug 18, 2011 at 17:50
-
\$\begingroup\$ Ok thanks, didn't know that! :) I put it in my previous answer. \$\endgroup\$Abbas– Abbas2011年08月18日 17:52:25 +00:00Commented 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\$Ed Swangren– Ed Swangren2011年08月19日 00:06:20 +00:00Commented Aug 19, 2011 at 0:06
-
\$\begingroup\$ Could also try some regex options depending on your use case \$\endgroup\$KyleMit– KyleMit ♦2018年09月28日 01:54:16 +00:00Commented Sep 28, 2018 at 1:54
5 Answers 5
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.
-
\$\begingroup\$ No prob! In general, if you have a
foreach
loop, you should try to "Think LINQ". \$\endgroup\$dlev– dlev2011年08月18日 17:50:48 +00:00Commented 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\$Matthew Abbott– Matthew Abbott2011年08月18日 17:58:50 +00:00Commented 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\$dlev– dlev2011年08月18日 17:59:51 +00:00Commented 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 theforeach
variant. \$\endgroup\$Matthew Abbott– Matthew Abbott2011年08月18日 18:03:17 +00:00Commented 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\$Jeff Mercado– Jeff Mercado2011年08月18日 22:29:24 +00:00Commented Aug 18, 2011 at 22:29
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);
}
static bool EndsWithOneOf(this string value, IEnumerable<string> suffixes)
{
return suffixes.Any(suffix => value.EndsWith(suffix));
}
Two advantages here:
- use of extension method makes calling this method more straight
forward (i.e.
mystring.EndsWithOneOf(mySuffixes);
) - Use of linq allows for better readability (see declarative vs imperative programming)
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
?
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.