Обратите внимание, что подпись типа вашей попытки неверна. Вы хотите, чтобы все комбинации разбиений подслов были списком строк, а ваш тип - просто списком строк.
Это будет работать:
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]
Он использует ту же технику, что и выше, только с более чистой реализацией.
Попробуйте это
var source = GetTheString();
var reversed = source.Reverse().Select(x => x.ToString()).Aggregate((x,y) => x + "." + y);
Править
Это решение определенно нацелено на "умный" конец. Это вероятно намного более производительное для использования StringBuilder для создания строки. Это решение создает много промежуточных строк.
EDIT2
Были некоторые дебаты об относительной скорости "умного" решения по сравнению с подходом StringBuilder. Я описал быстрый сравнительный тест для измерения подхода. Как ожидалось StringBuilder быстрее.
Однако, действительно ли различием в скорости является 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());
}
}
Преимущество этого является той Строкой. Соединение будет более дешевым, чем ".Aggregate ((x, y) => x +"." + y)".
var target = string.Join(".", source.Reverse().Select(c => c.ToString()).ToArray());
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(".");
}
string aString = "13335557777";
string reversed = (from c in aString.Reverse()
select c + ".").Aggregate((a, b) => a + b);
Пока Вы уже проходите массив, было бы легче использовать строку. Соединение:
string[] source = GetTheStringAsArray();
string reversed = string.Join(".", source.Reverse());
Это - действительно 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 также.
(удаленный ответ с помощью a char
список)
Согласно комментарию к другому сообщению, мое представление состоит в том, что, в то время как LINQ и т.д. может быть "умным", это не обязательно эффективно. Это сделает много промежуточных строк, которые должны быть собраны, например.
Я придерживался бы StringBuilder
и т.д., если у Вас нет серьезного основания изменить его.