问题
As a C# Novice, currently to find out the index of the first uppercase character in a string I have figured out a way
var pos = spam.IndexOf(spam.ToCharArray().First(s => String.Equals(s, char.ToUpper(s))));
Functionally the code works fine except that I was having the discomfort of traversing the string twice, once to find the Character and then the Index. Is there any possibility to get the index of the first UpperCase character in one pass using LINQ?
an equivalent way in C++ would be something like
std::string::const_iterator itL=find_if(spam.begin(), spam.end(),isupper);
an equivalent Python Syntax would be
next(i for i,e in enumerate(spam) if e.isupper())
回答1:
Well, if you just want to do it in LINQ
, you can try to use something like
(from ch in spam.ToArray() where Char.IsUpper(ch)
select spam.IndexOf(ch))
If you run this against string, say
"string spam = "abcdeFgihjklmnopQrstuv";"
the result would be: 5, 16
.
This will return expected result.
回答2:
Here is an answer based on @Tigran's but that will return the index of all capitals, even if there are duplicates:
from i in Enumerable.Range(0, searchText.Length - 1)
where Char.IsUpper(searchText.Chars[i]) select i
回答3:
Just because i often find people dont know:
Select has a way to get the index aswell as the item you are enumerating. Eventhough it gives a slight extra overhead you could do this:
var objectsWithCharAndIndex = myString.Select((c,i)=>new {Char = c,Index = i});
then its only a matter of doing:
var firstCapitalIndex = objectsWithCharAndIndex.First(o => Char.IsUpper(o.Char)).Index;
or return them all
var allCapitalIndexes = objectsWithCharAndIndex.Where(o => Char.IsUpper(o.Char)).Select(o=>o.Index);
of you could iterate through the objects if you need the char and the index together.
This is just normal Linq syntax, not Linq query syntax.
回答4:
No need for LINQ:
int index = 0;
foreach(Char c in myString)
{
if(Char.IsUpper(c)) break;
index++;
}
// index now contains the index of the first upper case character
This can be easily converted to an extension method, as @Tigran comments.
回答5:
Another possibility:
string s = "0123aBc";
int rslt = -1;
var ch = s.FirstOrDefault(c => char.IsUpper(c));
if (ch != 0)
rslt = s.IndexOf(ch);
And, if you're only concerned with English:
char[] UpperCaseChars = new char[]
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z'
};
int rslt = s.IndexOfAny(UpperCaseChars);
That's probably going to execute a lot faster than any of the others, and is what I'd use if I were doing this a lot.
Another possibility is to use a regular expression:
var match = Regex.Match(s, "\p{Lu}", RegexOptions.None);
int rslt = match.Success ? match.Index : -1;
That'll match any Unicode upper case character. If you want just English, change the expression to "[A-Z]"
.
回答6:
Linq does not provide an efficient way of doing this out of the box, but you can extend Linq to provide this capability very easily.
If you add this class to your solution:
internal static class EnumerableExtensions
{
public static int IndexOfNth<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate, int skip = 0)
{
var index = 0;
foreach (var value in enumerable)
{
if (predicate(value))
{
if (skip-- == 0)
return index;
}
index++;
}
return -1;
}
public static int IndexOfFirst<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
{
return enumerable.IndexOfNth(predicate);
}
}
Then you can write code like this that will be efficient and only enumerate the string once:
var firstUpper = spam[spam.IndexOfFirst(Char.IsUpper)];
Note: this blows up with index out of bounds if the string does not contain any upper case letters so you would need an extra check for IndexOfFirst
returning -1
.
With this implementation you can also find the 2nd upper case letter like this:
var secondUpper = spam[spam.IndexOfNth(Char.IsUpper, 1)];
And it works with any enumerable not just enumerations of chars, for example
var indexOfFirstManager = employees.IndexOfFirst(employee => employee.IsManager);
回答7:
String.Concat(
str.Select(c => Char.IsUpper(c) ? $" {c}" : $"{c}")
);
来源:https://stackoverflow.com/questions/10257711/find-index-of-the-first-uppercase-character