views:

175

answers:

8

I have a bunch of lat/long pairs as a string:

-94.5555,95.5555

The API I'm using requires they be switched:

95.555,-94.555

Is there any slick, short way of doing this?

+3  A: 

Just write a method to do it, e.g. using string.IndexOf:

// Probably rename to reflect your specific usage
private static string SwitchSplitOnComma(string text)
{
    // Optional: validate that text is non-null
    int comma = text.IndexOf(',');
    // Optional: validate that there's a comma :)
    return text.Substring(comma + 1) + "," + text.Substring(0, comma);
}

Unless you need this for various purposes, I'd leave it as a specialist method in the class that needs it. Only promote it to a "general purpose utility method" (possibly parameterizing the delimiter etc) if you find you need the same functionality elsewhere.

Although you can do this in a single statement, I think the code is likely to be far easier to understand if you put it in a separate method - at which point it's fine to use a few easy-to-understand statements instead of one complicated and inefficient one :)

Jon Skeet
Just as an aside, is there a reason you don't use String.Format? I always do, is there a reason I shouldn't that I don't know about? Not critiqueing, I just wonder why sometimes I see people doing it vs not doing it for concatenation..
Jimmy Hoffa
@Jimmy I beilive in a situation like this the compiler will optimize it.
asawyer
I'm guessing String.Format() is slower because it has to parse the string then replace values?
Nelson
Aye, just found another post about this, guess I should be using String.Concat, as + just reads grody to me.
Jimmy Hoffa
@Jimmy: "+" *does* use `String.Concat` under the covers, and IMO is more readable. As for using string.Format - again, I think that would be less readable than just stringing the values together, in this case.
Jon Skeet
I remember reading a post long ago which benchmarked StringBuilder vs. concatenation, and if you have less than ~4 strings, concatenation is faster. (String.Concat and String.Format both uses a StringBuilder internally)
Mikael Svenson
@Mikael: `String.Concat(string[])` uses unsafe code to allocate a single buffer for all of the strings and copy them into the buffer, not using a `StringBuilder` at all. `String.Concat` will always beat using a `StringBuilder` if the code is like `string s = a + b + c + d;` but not if there is a loop involved where strings are not concatenated inline. http://stackoverflow.com/questions/2708550/using-stringstringstring-vs-using-string-replace/2708565#2708565
Callum Rogers
@Callum: You are right. I read the IEnumberable variants for .Net4. for Concat.
Mikael Svenson
+12  A: 

One-liner with Linq:

string.Join(",", original.Split(',').Reverse());

Or, more explicit (might be a performance improvement):

string[] split = original.Split(',');
string reversed = split[1] + "," + split[0];
Matthew Flaschen
You'll want a `ToArray()` call after `Reverse` since LINQ's `Reverse` returns an `IEnumerable`, not an array, which `Join` wants.
Sarah Vessels
@Sarah: .NET 4 has new overloads for string.Join.
Jon Skeet
Ah, beautiful, thanks!
chum of chance
I know that we're talking about a lat/long pair, but watch out for the thousand separator should you except such data to be given to your function.
Pierre-Alain Vigeant
I have to use it in a non-static context so Join doesn't work. I gave Jon Skeet the best answer, but this was very pretty so I gave you a point.
chum of chance
What is it about your context that makes this approach not work?
recursive
@chum: Why would being in a non-static context stop `Join` from working? You can absolutely use this answer in any context you like. Personally I'd still rather have a well-named method call which hides the details, but this would definitely work.
Jon Skeet
The compiler is throwing up a warning: Cannot access static method 'Join' in non-static context. I didn't really investigate why though, it might be because my properties are virtual? public virtual string ReverseObject { get { return LatLong.Join... } } I agree with you on the well named-method calls though.
chum of chance
@chum: You've changed the code. It should be `string.Join`, not `LatLong.Join`. Replace `original` with `LatLong`, not `string`.
Jon Skeet
Duh, thanks Jon!
chum of chance
+1  A: 
string myStr = "-94.5555,95.5555";
string[] components = myStr.Split(",")
components.Reverse();
string flippedStr = string.Join(",", components);
Sarah Vessels
+3  A: 
String reversedLatLong = String.Join(",", yourString.Split(',').Reverse());
Jimmy Hoffa
A: 

The most efficient would be to modify/extend the API, since it parses the string anyway. Probably not an option, but I throw it out there...

Kendrick
A: 

How about this?

string oldString = "-94.5555,95.5555";
string newString = oldString .Substring(oldString .IndexOf(",") + 1) + "," + oldString .Substring(0, oldString .IndexOf(","));
Shoban
+2  A: 

Building on Jon Skeet's, something more generic would be useful:

private static string Switch(this string text, char splitter)
{
    if(text != null && text.Length > 2) //Needs at least 3 letters for a valid switch
    {
        int position = text.IndexOf(splitter);
        if(position != -1) return text.Substring(position + 1) + splitter + text.Substring(0, position);
    }
    return text;
}

"99,-3432".Switch(',');
Blam
A: 

Just for the heck of it. Here's a faster version, but you probably wouldn't need it :)

For 1.000.000 iterations compared to Jon Skeets clean version measured in seconds on my machine:

00:00:00.2145657 substring

00:00:00.0781270 unsafe

private unsafe static string SwitchSplitOnComma2(string text)
{
    int comma = text.IndexOf(',');
    string newString = string.Copy(text);
    fixed (char* src = text)
    {
        fixed (char* dst = newString)
        {
            int destCtr = 0;
            for (int i = comma + 1; i < text.Length; i++)
            {
                dst[destCtr++] = src[i];
            }
            dst[destCtr++] = ',';
            for (int i = 0; i < comma; i++)
            {
                dst[destCtr++] = src[i];
            }
        }
    }
    return newString;
}
Mikael Svenson