I'm doing a project where I am trying to convert snake case strings into camel case, but when I run my code CS0029 is thrown. I have no idea why this is happening.
using System;
using System.Linq;
public class Kata
{
public static string ToCamelCase(string str)
{
string[] strSplit = str.Split(new char[] { '-', '_' });
// this query is throwing an error
int firstWordIndex = from s in strSplit
where s != "-" || s != "_"
select Array.IndexOf(strSplit, s);
string firstWord = strSplit[firstWordIndex];
var camelCase = from s in strSplit
where Array.IndexOf(strSplit, s) != firstWordIndex
select s.Replace(s[0], Char.ToUpper(s[0]));
return string.Concat(firstWord, string.Join("", camelCase));
}
}
CodePudding user response:
You can't do this:
int firstWordIndex = from s in strSplit
where s != "-" || s != "_"
select Array.IndexOf(strSplit, s);
When you Select from an enumerable thing (e.g. an array like Split gives you), you get another enumerable thing even if you put a where clause that ensures the new enumerable thing will have only one element
var array = new[]{ "a","b","c"}
array.Where(x => x == "a").Select(..) //returns you an "array" with only one element
If you want just one thing out of an enumerable, look at something like First()
int firstWordIndex = (
from s in strSplit
where s != "-" || s != "_"
select Array.IndexOf(strSplit, s)
)
.First();
First()
(and its buddies FirstOrDefault
, Single[OrDefault]
, Last[OrDefault]
) will return you just one T
out of an IEnumerable<T>
. They accept a lambda that you could use instead of a Where, too (it would look like Array.IndexOf(strSplit, strSplit.First(s => s != "-" || s != "_")
)
Also want to point out that s != "-" || s != "_"
is surely true for every string in the world, because "-" != "_"
- as a human you might say "get every ball out of this box that is not red or blue" but that means not(red or blue)
, which is equivalent to (not red) AND (not blue)
.
"not red or not blue" is always true because a red ball isn't blue and a blue ball isn't red, and a green ball is not red also (C# doesn't bother checking if a green ball is blue :D )
Common trap; watch out for it
I would have dug deeper into fixing your code, but for what it's worth, if I was writing a camelcaser I probably wouldn't use LINQ at all because there's a great risk it could become a very convoluted, low performance affair; even in the code as you have it, you split, then you loop (LINQ does a lot of looping internally) to find any char that isn't X, then you loop again (Array IndexOf) to find the index of that.. It would be a slight optimization to switch to method syntax, as Select((element, index) => index)
could be used to return the index of the char without looping again but..
I'd probably lower the whole thing, turn it into a char array, loop over it and if the previous char was Char.IsPunctuation/IsWhitespace and the current char is not, I'd Char.ToUpper it otherwise Char.ToLower it, then remove the spaces.. If they were long strings I'd use a stringbuilder and not insert spaces into it. See https://docs.microsoft.com/en-us/dotnet/api/system.char.ispunctuation?view=net-5.0