Проблема обработки строк C#

Обратите внимание, что подпись типа вашей попытки неверна. Вы хотите, чтобы все комбинации разбиений подслов были списком строк, а ваш тип - просто списком строк.

Это будет работать:

onHead :: (a -> a) -> [a] -> [a]
onHead _ [] = []
onHead f (x:xs) = f x:xs

combos :: [a] -> [[[a]]]
combos [] = [[]]
combos [x] = [[[x]]]
combos (x:xs) = [([x]:), onHead (x:)] <*> combos xs

onHead должно быть самоочевидным: выполнить данную функцию в начале списка. combos повторяется следующим образом: подсловами строки являются подсловы ее хвоста, с двумя вариантами для каждого: либо заголовок является своим собственным подсловом, либо он прикреплен к началу первого подслово.


Обновление: вот еще один подход (чище IMO):

combos :: Foldable t => t a -> [[[a]]]
combos = foldr (concatMap . go) [[]]
  where go x [] = [[[x]]]
        go x l@(h:t) = [[x]:l, (x:h):t]

Он использует ту же технику, что и выше, только с более чистой реализацией.

5
задан Andy White 24 March 2009 в 23:00
поделиться

7 ответов

Попробуйте это

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

Править

Это решение определенно нацелено на "умный" конец. Это вероятно намного более производительное для использования StringBuilder для создания строки. Это решение создает много промежуточных строк.

EDIT2

Были некоторые дебаты об относительной скорости "умного" решения по сравнению с подходом StringBuilder. Я описал быстрый сравнительный тест для измерения подхода. Как ожидалось StringBuilder быстрее.

  • Нормальный Агрегат (100 элементов): 0:00:00.0418640
  • WithStringBuilder (100 элементов): 0:00:00.0040099
  • Нормальный Агрегат (1 000 элементов): 0:00:00.3062040
  • WithStringBuilder (1 000 элементов): 0:00:00.0405955
  • Нормальный Агрегат (10 000 элементов): 0:00:03.0270392
  • WithStringBuilder (10 000 элементов): 0:00:00.4149977

Однако, действительно ли различием в скорости является signficant, очень зависит от того, где это на самом деле используется в Вашем приложении.

Код для сравнительного теста.

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());
    }
}
8
ответ дан 13 December 2019 в 22:16
поделиться

Преимущество этого является той Строкой. Соединение будет более дешевым, чем ".Aggregate ((x, y) => x +"." + y)".

var target = string.Join(".", source.Reverse().Select(c => c.ToString()).ToArray());
2
ответ дан 13 December 2019 в 22:16
поделиться
        string x = "123456";
        StringBuilder y = new StringBuilder(x.Length * 2);

        for (int i = x.Length - 1; i >= 0; i--)
        {
            y.Append(x[i]);
            y.Append(".");
        }
1
ответ дан 13 December 2019 в 22:16
поделиться
string aString = "13335557777";
string reversed = (from c in aString.Reverse()
                 select c + ".").Aggregate((a, b) => a + b);
0
ответ дан 13 December 2019 в 22:16
поделиться

Пока Вы уже проходите массив, было бы легче использовать строку. Соединение:

string[] source = GetTheStringAsArray();
string reversed = string.Join(".", source.Reverse());
-1
ответ дан 13 December 2019 в 22:16
поделиться

Это - действительно linq проблема? Просто работайте назад в цикле на символ:

string s = "";
string content = "35557777";
for (int i = content.Length -1; i > 0; i--)
{
    s += content[i] + ".";
}
Console.WriteLine(s);
Console.ReadLine();

Если это - строка дольше, чем 4k, используйте StringBuilder. Используя LINQ для "7.7.7.7.5.5.5.3.3.3.1". не то, для чего LINQ, отметьте меня к-99, если Вы хотите, и Marc также.

0
ответ дан 13 December 2019 в 22:16
поделиться

(удаленный ответ с помощью a char список)

Согласно комментарию к другому сообщению, мое представление состоит в том, что, в то время как LINQ и т.д. может быть "умным", это не обязательно эффективно. Это сделает много промежуточных строк, которые должны быть собраны, например.

Я придерживался бы StringBuilder и т.д., если у Вас нет серьезного основания изменить его.

0
ответ дан 13 December 2019 в 22:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: