c # лямбда, LINQ .... улучшить этот метод - PullRequest
5 голосов
/ 27 марта 2009

Я нахожусь в процессе изучения дополнительных сведений о выражениях LINQ и Lambda, но на данном этапе я просто не "получаю" выражения Lambda.

Да ... Я новичок в этих новых понятиях.

Я имею в виду, что каждый пример, который я вижу, иллюстрирует, как добавлять или вычитать параметры.

Как насчет чего-то более сложного?

Чтобы помочь мне лучше понять, я отправил небольшую задачу для всех, кто хочет участвовать. У меня есть следующий метод, который будет принимать любую строку и ставить пробелы между любыми символами верхнего регистра и их предшествующим соседом (как показано ниже).

1011 * т.е. * "SampleText" = "Образец текста"
"DoesNotMatterHowManyWords" = "Не важно, сколько слов"

Вот код;

public static string ProperSpace(string text)
{
    var sb = new StringBuilder();
    var lowered = text.ToLower();

    for (var i = 0; i < text.Length; i++)
    {
        var a = text.Substring(i, 1);
        var b = lowered.Substring(i, 1);
        if (a != b) sb.Append(" ");
        sb.Append(a);
    }

    return sb.ToString().Trim();
}

Я уверен, что описанный выше метод можно переписать для использования с LINQ или лямбда-выражением. Я надеюсь, что это упражнение поможет мне открыть глаза на эти новые концепции.

Также, если у вас есть хорошие ссылки на учебные пособия по LINQ или Lambda, пожалуйста, предоставьте.


EDIT

Спасибо всем, кто внес свой вклад. Хотя текущий метод выполняет свою работу, я рад видеть, что его можно изменить, чтобы использовать лямбда-выражение. Я также признаю, что это, возможно, не лучший пример для LINQ.

Вот недавно обновленный метод, использующий лямбда-выражение (проверено на работу);

public static string ProperSpace(string text)
{
    return text.Aggregate(new StringBuilder(), (sb, c) =>
    {
        if (Char.IsUpper(c)) sb.Append(" ");
        sb.Append(c);
        return sb;
    }).ToString().Trim();
}

Я также ценю множество ссылок на другие (похожие) темы.

В частности эта тема , что так верно.

Ответы [ 11 ]

5 голосов
/ 27 марта 2009

Это происходит так же, как и в исходном коде, и даже позволяет избежать генерации второй (строчной) строки.

var result = text.Aggregate(new StringBuilder(), 
    (sb, c) => (Char.IsUpper(c) ? sb.Append(' ') : sb).Append(c));
5 голосов
/ 27 марта 2009

Лично я думаю, что ваш метод прост и понятен, и я бы придерживался его (я думаю, что я мог бы даже написать точно такой же код где-то вдоль строк).

UPDATE:

Как насчет этого как отправной точки?

public IEnumerable<char> MakeNice(IEnumerable<char> str)
{
  foreach (var chr in str)
  {
    if (char.ToUpper(chr) == chr)
    {
      yield return ' ';
    }
    yield return chr;
  }
}

public string MakeNiceString(string str)
{
  return new string(MakeNice(str)).Trim();
}
3 голосов
/ 27 марта 2009
public static string ProperSpace(string text)
{
    return text.Aggregate(new StringBuilder(), (sb, c) =>
        {
            if (Char.IsUpper(c) && sb.Length > 0)
                sb.Append(" ");

            sb.Append(c);
            return sb;
        }).ToString();
}
3 голосов
/ 27 марта 2009

Как и Леппи, я не уверен, что это хороший кандидат на LINQ. Конечно, это можно заставить, но это не будет полезным примером. Небольшой твик будет сравнивать text[i] с lowered[i], чтобы избежать ненужных строк - и, возможно, по умолчанию sb будет new StringBuilder(text.Length) (или немного выше):

if (text[i] != lowered[i]) sb.Append(' ');
sb.Append(a);

Кроме этого - я бы оставил это в покое;

2 голосов
/ 27 марта 2009

Я бы использовал RegularExpressions для этого случая.

public static string ProperSpace(string text)
{
  var expression = new Regex("[A-Z]");
  return expression.Replace(text, " $0");
}

Если вы хотите использовать лямбду, вы можете использовать:

public static string ManipulateString(string text, Func<string, string> manipulator)
{
    return manipulator(text);
}
// then
var expression = new Regex("[A-Z]");
ManipulateString("DoesNotMatterHowManyWords", s => expression.Replace(text, " $0"));

Что по сути аналогично использованию анонимного делегата

var expression = new Regex("[A-Z]");
ManipulateString("DoesNotMatterHowManyWords", delegate(s) {
  return expression.Replace(text, " $0")
});
1 голос
/ 27 марта 2009

Вот способ сделать это:

string.Join("", text.Select((c, i) => (i > 0 && char.IsUpper(c)) ? " " + c : c.ToString()).ToArray());

Но я не вижу, где улучшение. Просто отметьте этот самый последний вопрос ...

РЕДАКТИРОВАТЬ: Для тех, кто задается вопросом: да, я намеренно выбрал ужасное решение.

0 голосов
/ 30 сентября 2010

Вы когда-нибудь задумывались об использовании функции Aggregate ...

Например, допустим, у меня есть массив с именем маршрутов, и я хочу установить для всех активных полей значение false. Это можно сделать следующим образом:

rout.Aggregate (false, (значение, маршрут) => route.Active = false); - Маршруты это имя таблицы. - Первое ложное значение - это просто начальное значение, и оно должно быть того же типа, что и устанавливаемое значение. Это вроде ... избыточно. - значение также является избыточным и в основном является первым значением. - маршрут - совокупное значение (каждый отдельный элемент из последовательности)

Больше нет лишних циклов foreach ... Я тоже не очень хорошо знаю лямбда-выражения ... но я уверен, что где-то есть гений, который может злоупотребить этим, чтобы сделать это ...

0 голосов
/ 27 марта 2009

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

public static string ProperCase(string text)
{
    return text.Aggregate(
        string.Empty,
        (acc, c) => Char.ToLower(c) != c ? acc + " " + c.ToString() : acc + c.ToString())
        .Trim();
}
0 голосов
/ 27 марта 2009

У меня есть решение Regex, которое всего в 8 раз медленнее, чем ваш текущий цикл [1], и труднее для чтения, чем ваше решение [2].

return Regex.Replace(text, @"(\P{Lu})(\p{Lu})", "$1 $2");

Соответствует юникоду группам символов, в этом случае не заглавными буквами, затем заглавными, а затем между ними добавляется пробел. Это решение работает лучше, чем другие решения на основе регулярных выражений, которые ищут только [A-Z].

[1] С оговорками, что мой быстро составленный тест может не сработать.
[2] Кто-нибудь на самом деле знает группы символов Unicode без поиска в Google? ;)

0 голосов
/ 27 марта 2009

Для полезности linq (если вам нужно убедить), вы можете проверить этот вопрос.

Я думаю, что первый шаг - это привыкнуть к синтаксису точек, и только потом переходить к синтаксису 'sql'. В противном случае это просто повредит вашим глазам, чтобы начать с. Я действительно задаюсь вопросом, не замедлила ли Microsoft освоение linq, продвигая синтаксис sql, что заставило многих задуматься: «Черт, код БД в моем C #».

Что касается лямбд, сначала попробуйте написать код с анонимными делегатами, потому что, если вы этого не сделали, вы не поймете, в чем суть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...