How to optimize and precompile this LINQ expression?

Given the following input for 60%toleration

"STACKOVERflow is a quesTions and ANSwers weBSITE"

I expect the following conclusion

// Extra spaces just to show %s
// 69%          50%  100%  22%!      33% 42%     14%
"Stackoverflow  Is   A     QuesTions And ANSwers Website"

Questionsand Answershave uppercase characters, but they are less than 60%strings, so you should keep it. And then I want to convert the first character of each line to uppercase.

I am currently using this method

public static class StringExtender
{
    public static string ToTitleCase(this string str, double preserve)
    {
        return String.Join(" ",
            str.Split(' ')
            .Select(x => (x.Count(y => y.ToString() == y.ToString().ToUpper()) / (double)x.Length * 100) > preserve ? x.ToLower() : x)
            .Select(x =>
                String.Join(String.Empty,
                    x.Select((y, z) => z == 0 ? y.ToString().ToUpper() : y.ToString()).ToArray()
                )
            ).ToArray()
        );
    }
}

At the first start, I get 15000ticks ( Stopwatch.EllapsedTicks), and the next ones in 300. It seems that for the first time he is doing some kind of compilation ...

  • Is there a way to compile it at run time, so the first time it runs it uses full speed, as in the next?
  • Is there a way to optimize this code even more?

Full code (to include measurement methods)

using System;
using System.Diagnostics;
using System.Linq;

public static class StopwatchExtender
{
    public static void Timer(this Stopwatch sw, Action x, int iterations, string name)
    {
        sw.Start();
        for (int i = 0; i < iterations; ++i)
        {
            x();
        }
        sw.Stop();

        Console.WriteLine("Name: {0}\nTicks: {1}\n", name, sw.ElapsedTicks);

        sw.Reset();
    }
}

public static class StringExtender
{
    public static string OP(this string str, double preserve)
    {
        return String.Join(" ",
            str.Split(' ')
            .Select(x => (x.Count(y => y.ToString() == y.ToString().ToUpper()) / (double)x.Length * 100) > preserve ? x.ToLower() : x)
            .Select(x =>
                String.Join(String.Empty,
                    x.Select((y, z) => z == 0 ? y.ToString().ToUpper() : y.ToString()).ToArray()
                )
            ).ToArray()
        );
    }

    public static string A01(this string str, double preserve)
    {
        return string.Join(" ",
            str.Split(' ')
                .Select(s => char.ToUpper(s[0]) + ((s.Count(c => char.IsUpper(c)) / (double)s.Length * 100) > preserve ? s.Substring(1).ToLower() : s.Substring(1)))
                .ToArray()
            );
    }
}

public class Program
{
    static void Main()
    {
        var sw = new Stopwatch();

        var str = "STACKOVERflow is a quesTions and ANSwers weBSITE";

        sw.Timer(() =>
        {
            str.OP(60);
            str.A01(60);
        }, 1, "Starup takes more time");

        sw.Timer(() =>
        {
            str.OP(60);
        }, 1000000, "OP solution");

        sw.Timer(() =>
        {
            str.A01(60);
        }, 1000000, "LukeH answer");

        Console.ReadLine();
    }
}

results

results

+3
2
public static string ToTitleCase(this string str, double preserve)
{
    return string.Join(" ",
        str.Split(' ')
           .Select(s => s.Length == 0 ? s : char.ToUpper(s[0]) + ((s.Count(c => char.IsUpper(c)) / (double)s.Length * 100) > preserve ? s.Substring(1).ToLower() : s.Substring(1)))
           .ToArray());
}

( ToArray, .NET 4.)

+3

Source: https://habr.com/ru/post/1769533/


All Articles