Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# string manipulation problem

Tags:

string

c#

linq

Here's a simple problem. I have an application that takes a phone number like "13335557777", and needs to reverse it and insert a dot between each number, like this:

"7.7.7.7.5.5.5.3.3.3.1."

I know I can do this with a StringBuilder and a for-loop to reverse the string and insert the dots, but is there a clever way to do this in LINQ (or some other way)?

Note: for this, I'm not really concerned with performance or memory allocation or whatever, just curious to see how this would be done in LINQ.

like image 224
Andy White Avatar asked Mar 24 '09 22:03

Andy White


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.

What is C in C language?

What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.


2 Answers

Try this

var source = GetTheString();
var reversed = source.Reverse().Select(x => x.ToString()).Aggregate((x,y) => x + "." + y);

EDIT

This solution is definitely aimed at the "clever" end. It's likely much more performant to use a StringBuilder to build up the string. This solution creates many intermediate strings.

EDIT2

There was some debate about the relative speed of the "clever" solution vs. the StringBuilder approach. I wrote up a quick benchmark to measure the approach. As expected, StringBuilder is faster.

  • Normal Aggregate (100 elements): 00:00:00.0418640
  • WithStringBuilder (100 elements): 00:00:00.0040099
  • Normal Aggregate (1000 elements): 00:00:00.3062040
  • WithStringBuilder (1000 elements): 00:00:00.0405955
  • Normal Aggregate (10000 elements): 00:00:03.0270392
  • WithStringBuilder (10000 elements): 00:00:00.4149977

However, whether or not the speed difference is signficant is highly dependent upon where it is actually used in your application.

Code for the benchmark.

public static class AggregateUnchanged {
    public static string Run(string input) {
        return input
            .Reverse()
            .Select(x => x.ToString())
            .Aggregate((x, y) => x + "." + y);
    }
}

public static class WithStringBuilder {
    public static string Run(string input) {
        var builder = new StringBuilder();
        foreach (var cur in input.Reverse()) {
            builder.Append(cur);
            builder.Append('.');
        }

        if (builder.Length > 0) {
            builder.Length = builder.Length - 1;
        }

        return builder.ToString();
    }
}

class Program {
    public static void RunAndPrint(string name, List<string> inputs, Func<string, string> worker) {

        // Test case. JIT the code and verify it actually works 
        var test = worker("123456");
        if (test != "6.5.4.3.2.1") {
            throw new InvalidOperationException("Bad algorithm");
        }

        var watch = new Stopwatch();
        watch.Start();
        foreach (var cur in inputs) {
            var result = worker(cur);
        }
        watch.Stop();
        Console.WriteLine("{0} ({2} elements): {1}", name, watch.Elapsed, inputs.Count);
    }

    public static string NextInput(Random r) {
        var len = r.Next(1, 1000);
        var builder = new StringBuilder();
        for (int i = 0; i < len; i++) {
            builder.Append(r.Next(0, 9));
        }
        return builder.ToString();
    }

    public static void RunAll(List<string> input) {
        RunAndPrint("Normal Aggregate", input, AggregateUnchanged.Run);
        RunAndPrint("WithStringBuilder", input, WithStringBuilder.Run);
    }

    static void Main(string[] args) {
        var random = new Random((int)DateTime.Now.Ticks);
        RunAll(Enumerable.Range(0, 100).Select(_ => NextInput(random)).ToList());
        RunAll(Enumerable.Range(0, 1000).Select(_ => NextInput(random)).ToList());
        RunAll(Enumerable.Range(0, 10000).Select(_ => NextInput(random)).ToList());
    }
}
like image 71
JaredPar Avatar answered Sep 20 '22 22:09

JaredPar


The benefit of this one is that String.Join is going to be cheaper than ".Aggregate((x,y) => x + "." + y)".

var target = string.Join(".", source.Reverse().Select(c => c.ToString()).ToArray());
like image 27
Jonathan Allen Avatar answered Sep 20 '22 22:09

Jonathan Allen