Методы, которые что-то ищут, но могут не найти
А можно чуть более реальный пример? Например, через TryParse и IndexOf можно решить такую задачу: есть строка, в которой идут целые числа, разделенные пробелами ("12 34 567 8" найти их сумму. Как это будет выглядеть при твоем подходе?
callback усложняет логику кода.
без колбаков - мы имеем однородный последовательный порядок выполнения: запрос, ответ, запрос, ответ.
с колбаками - мы фактически получаем прыгающее спагети, в котором сходу сказать, что за чем будем выполняться очень тяжело.
или другими словами без колбаков - мы имеем последовательность четко друг от друга отделенных атомарных конструкций, с колбаками мы получаем монолитный код - который за раз делает все.
здесь я кстати разделяю лямбды и колбаки.
колбак - это когда внутри делегата происходит изменение внешнего мира, лямбда - это когда происходит замыкание по чтению внешнего мира на внутренний.
возьмем, например, вот такой кусок код:
int? result = int.TryParse(value);
if (result != null)
{
Console.WriteLine("i = {0}", result);
}
else
{
Console.WriteLine("conversion failed");
}
здесь все четко - есть атомарная конструкция разбора числа, есть атомарная конструкция вывода значения
а вот здесь уже у нас монолитная конструкция, в которой уже трудно отделить разбор значения от вывода.
IntEx.Parse(
"123",
i => Console.WriteLine("i = {0}", i
=> Console.WriteLine("conversion failed")
;
А вообще это чем-то напоминает continuation-passing style.
2) Вроде как для таких ситуаций, когда нужно возвращать и значение и ошибку, придуман механизм исключений.
А можно чуть более реальный пример? Например, через TryParse и IndexOf можно решить такую задачу: есть строка, в которой идут целые числа, разделенные пробелами ("12 34 567 8" найти их сумму. Как это будет выглядеть при твоем подходе?Вот так
public static Action Sum(string str,
Action<int> successAction, Action failedAction)
{
int sum = 0;
int toIndex = 0;
while (true)
{
string subString = default(string);
bool isContinueFind = default(bool);
Action beforeContinueFindAction = default(Action);
Util.IndexOf(
str, " ", toIndex,
index =>
{
subString = str.Substring(toIndex, index - toIndex);
isContinueFind = true;
beforeContinueFindAction = => toIndex = index + 1;
},
=>
{
subString = str.Substring(toIndex);
isContinueFind = false;
beforeContinueFindAction = => { throw new ApplicationException; };
};
bool isParsed = default(bool);
IntEx.Parse(
subString,
i =>
{
sum += i;
isParsed = true;
},
=>
{
isParsed = false;
};
if (isParsed == false)
{
return failedAction;
}
if (isContinueFind == false)
{
break;
}
else
{
beforeContinueFindAction;
}
}
return => successAction(sum);
}
См. продолжение в следующих постах.
или returnreturn можно сделать, но для полноты придется задваивать методы. К сожалению, нет типа void
public class Util
{
public static Func<Tresult> IndexOf<Tresult>(string arg, string value, int startIndex,
Func<int, Tresult> successAction, Func<Tresult> failedAction)
{
int indexOf = arg.IndexOf(value, startIndex);
if (indexOf == -1)
{
return failedAction;
}
else
{
return => successAction(indexOf);
}
}
public static Action IndexOf(string arg, string value, int startIndex,
Action<int> successAction, Action failedAction)
{
var result = IndexOf<object>(
arg, value, startIndex,
i =>
{
successAction(i);
return null;
},
=>
{
failedAction;
return null;
}
);
return => result;
}
}
Замечу, что исходный метод string.IndexOf естественным образом выражается через Util.IndexOf
int indexOf = Util.IndexOf("aaa", "a", 0,
index => index, => -1;
при этом пользователь сам определяет, что возвращать, если символ не найден.
public static Func<Tresult> Sum<Tresult>(string str,
Func<int, Tresult> successFunc, Func<Tresult> failedFunc)
{
int sum = 0;
int toIndex = 0;
while (true)
{
bool isContinueFind = default(bool);
Action beforeContinueFindAction = default(Action);
if (IntEx.Parse(
Util.IndexOf(
str, " ", toIndex,
index =>
{
isContinueFind = true;
beforeContinueFindAction = => toIndex = index + 1;
return str.Substring(toIndex, index - toIndex);
},
=>
{
isContinueFind = false;
beforeContinueFindAction = => { throw new ApplicationException; };
return str.Substring(toIndex);
}
i =>
{
sum += i;
return true;
},
=> false
== false)
{
return failedFunc;
}
if (isContinueFind == false)
{
break;
}
else
{
beforeContinueFindAction;
}
}
return => successFunc(sum);
}
public static Func<TResult> Sum<TResult>(string str,
Func<int, TResult> successFunc, Func<TResult> failedFunc)
{
int sum = 0;
int toIndex = 0;
while (true)
{
var findController = Util.IndexOf<IFindController>(
str, " ", toIndex,
index => new ContinueFindController(
str.Substring(toIndex, index - toIndex
=> toIndex = index + 1
=> new BreakFindController(str.Substring(toIndex
;
if (IntEx.Parse(
findController.FoundString,
i =>
{
sum += i;
return true;
},
=> false
== false)
{
return failedFunc;
}
if (findController.IsContinue == false)
{
break;
}
else
{
findController.BeforeContinue;
}
}
return => successFunc(sum);
}
private interface IFindController
{
string FoundString { get; }
bool IsContinue { get; }
void BeforeContinue;
}
private class ContinueFindController : IFindController
{
private readonly string foundString;
private readonly Action beforeContinueFindAction;
public ContinueFindController(string foundString, Action beforeContinueFindAction)
{
this.foundString = foundString;
this.beforeContinueFindAction = beforeContinueFindAction;
}
public string FoundString
{
get { return foundString; }
}
public bool IsContinue
{
get { return true; }
}
public void BeforeContinue
{
beforeContinueFindAction;
}
}
private class BreakFindController : IFindController
{
private readonly string foundString;
public BreakFindController(string foundString)
{
this.foundString = foundString;
}
public string FoundString
{
get { return foundString; }
}
public bool IsContinue
{
get { return false; }
}
public void BeforeContinue
{
throw new ApplicationException;
}
}
P.S. пока это эксперимент, сильно не бейте
на остальные посты отвечу чуть позже
А с оригинальными функциями это может выглядеть так:
static int Sum(string str)
{
int i, sum_rest = 0, first_num;
if i = str.IndexOf(' ' >= 0)
{
sum_rest = Sum(str.Substring(i + 1;
str = str.Substring(0, i);
}
if (int.TryParse(str, out first_num
return first_num + sum_rest;
else
throw new ApplicationException("can't convert to number");
}
Теперь сравни сложность обоих подходов и вероятность внесения ошибки. Действительно ли есть какой-то выигрыш?
во-вторых, зачем рекурсия и постоянные пробеги по строке
в-третьих, я бы что-нибудь такое написал
это если нужно свое исключение
static int Sum(string str)
{
try
{
return str.Split(' ').Sum(value => int.Parse(value;
}
catch(FormatException exc)
{
throw new ApplicationException("can't convert to number", exc);
}
}
а это если нужно проигнорировать невалидные числа
static int Sum(string str)
{
return str.Split(' ').Sum(value => Util.Parse(value ? 0;
}
class Util
{
static public int? Parse(string value)
{
int result;
if (int.TryParse(value, out result
return result;
return null;
}
}
постоянные пробеги по строкеэто условие задачи
через TryParse и IndexOf можно решить такую задачу
IEnumerable<string> Split(string str)
{
var index = 0;
for (;;)
{
var pos = str.IndexOf(index, ' ');
if (pos == -1)
break;
yield return str.Substring(index, pos-index-1);
index = pos+1;
}
if (index < str.Length)
yield return str.Substring(index);
}
допустим у нас по ходу написания программы возникла задача отладки: необходимо вывести на консоль в строку через запятую части, на которые мы побили строку через indexOf.
как ты эту задачу будешь решать?
в коде с атомарными операциями все просто: код отладки просто вставляется между кодом разбора и суммирования
int Sum(string str)
{
var values = str.Split;
Console.WriteLine(values.JoinToString(", ";
return values.Sum(value => int.Parse(value;
}
А во-вторых, нафига, прости, ты откладываешь вызов коллбэка? Я понимаю, что это очень крутая фишка, но надо всё-таки на пользу смотреть, а не на количество и крутизну использованных фишек. Откладывая вызов ты никогда не сделаешь ничего полезного, я гарантирую это, зато можешь сделать что-нибудь неожиданное и вредное.
Получилось как я ожидал - смесь функциональщины с императивщиной с активной передачей состояния через переменные (сайд эффекты).Это просто другой алгоритм, давай сравнивать записи на языке C# одного алгоритма. Вот как твой алгоритм выглядит в моей записи.
А с оригинальными функциями это может выглядеть так:
Теперь сравни сложность обоих подходов и вероятность внесения ошибки. Действительно ли есть какой-то выигрыш?
static int Sum2(string str)
{
int sum_rest = 0;
Util.IndexOf(
str, " ", 0,
index =>
{
sum_rest = Sum2(str.Substring(index + 1;
str = str.Substring(0, index);
},
=> { }
;
return IntEx.Parse(
str,
i => i + sum_rest,
=>
{
throw new ApplicationException("can't convert to number");
}
;
}
в первую очередь мне не нравится твой код тем, что не понятно как его модифицировать дальше.у тебя в последнем варианте метод Split возвращает IEnumerable<string>, у этого типа нет метода JoinToString
допустим у нас по ходу написания программы возникла задача отладки: необходимо вывести на консоль в строку через запятую части, на которые мы побили строку через indexOf.
как ты эту задачу будешь решать?
в коде с атомарными операциями все просто: код отладки просто вставляется между кодом разбора и суммирования
code:
int Sum(string str)
{
var values = str.Split;
Console.WriteLine(values.JoinToString(", ";
return values.Sum(value => int.Parse(value;
}
В моем алгоритме распечатать все не всегда возможно, поскольку поиск чисел и суммирование идет в один проход.
Можно печатать найденные числа (если заморачиваться на то, чтобы не было лишней запятой, то как-то так)
private class Writer
{
private bool start = true;
public void Write(string s)
{
if (start == false)
{
Console.Write(", ");
}
Console.Write(s);
start = false;
}
public void EndWrite
{
Console.WriteLine;
}
}
public static Func<TResult> Sum<TResult>(string str,
Func<int, TResult> successFunc, Func<TResult> failedFunc)
{
int sum = 0;
int toIndex = 0;
var writer = new Writer;
while (true)
{
var findController = Util.IndexOf<IFindController>(
str, " ", toIndex,
index => new ContinueFindController(
str.Substring(toIndex, index - toIndex
=> toIndex = index + 1
=> new BreakFindController(str.Substring(toIndex
;
writer.Write(findController.FoundString);
if (IntEx.Parse(
findController.FoundString,
i =>
{
sum += i;
return true;
},
=> false
== false)
{
return failedFunc;
}
if (findController.IsContinue == false)
{
break;
}
else
{
findController.BeforeContinue;
}
}
writer.EndWrite;
return => successFunc(sum);
}
у тебя в последнем варианте метод Split возвращает IEnumerable<string>, у этого типа нет метода JoinToStringда, нет такого метода
зато есть такой код дополнительно
public static class StringHlp
{
public static string JoinToString(this IEnumerable<string> items, string separator)
{
return string.Join(separator, items.ToArray;
}
}
Замечу, что исходный метод string.IndexOf естественным образом выражается через Util.IndexOfя тут был не до конца прав, в случае TryParse эквивалентной записи нет. Такая запись
code:
int indexOf = Util.IndexOf("aaa", "a", 0,
index => index, => -1;
при этом пользователь сам определяет, что возвращать, если символ не найден.
int result = default(int);
IntEx.Parse(
"123",
i =>
{
result = i;
return true;
},
=>
{
result = default(int);
return false;
};
хуже, чем out параметром, приходится инициализировать переменную, да и переменных получается два i, result. Но такая ситуация возникает только, если надо использовать break или continue (см. пост выше). Причем есть возможность написать боле безопасный код, чем с out параметром (хотя и более громоздкий код получается)
var parseResult = IntEx.Parse<IParseResult>(
"123",
i => new SuccessParseResult(i
=> new FailedParseResult
;
private interface IParseResult
{
bool IsParsed { get; }
int Value { get; }
}
private class SuccessParseResult: IParseResult
{
private readonly int value;
public SuccessParseResult(int value)
{
this.value = value;
}
public bool IsParsed
{
get { return true; }
}
public int Value
{
get { return value; }
}
}
private class FailedParseResult : IParseResult
{
public bool IsParsed
{
get { return false; }
}
public int Value
{
get
{
throw new ApplicationException;
}
}
}
Здесь мы хотя бы в рантайме кидаем исключение (при чтении кода тоже видно, что в эту ветку исполнение не должно заходить в случае с out параметром переменную можно использовать даже, когда метод вернул false.
зато есть такой код дополнительноух, не привык я еще к расширенным методам .
Но суть дискуссии — сравнить записи одного и того же алгоритма. Твой алгоритм тоже записывается с помощью моего подхода.
прыгающее спагетиэто что-то новое , обычно спагетти называют как раз код, который тянется в линию, разветвляется и запутывается, как спагетти. Как раз там передают данные типа флажков, null-ов и "-1".
int? result = int.TryParse(value);
if (result != null)
{
Console.WriteLine("i = {0}", result);
}
else
{
Console.WriteLine("conversion failed");
}
--------------------------------------------------------------------------------
здесь все четко - есть атомарная конструкция разбора числа, есть атомарная конструкция вывода значения
я бы не сказал, что тут все четко. Разбираем число и получаем null, совсем не очевидно, что его следует интерпретировать, как не удачный разбор.
IntEx.Parse(
"123",
i => Console.WriteLine("i = {0}", i
=> Console.WriteLine("conversion failed")
;
А вот тут как раз все четко. Метод принимает два "куска кода", выбирает один из них, и возвращает в качестве результата. Ни каких специальных договоренностей не нужно.
P.S. пока это эксперимент, сильно не бейтеесли забить на потери пефоманса из-за создания Controller-ов, мне этот вариант начинает нравиться
int Sum(string str)
{
var values = str.Split;
return values.Sum(value => int.Parse(value;
}
Варианты ответа:
1. Читаемостью
2. Удобством отладки
3. Свой вариант
зато он внушает
не знаю что остальным, а мне он внушает отвращение. Зачем простую задачу решать сложно?
А последний разве работает?
Прямо щас под рукой настоящего компилятора нет, проверить не могу. Встроенный же в мозг, ошибок не выдает.
Чем твой код на 142 строчки лучше -евского:По ссылке всего 98 строк, я чего-то не понял?
code:
int Sum(string str)
{
var values = str.Split;
return values.Sum(value => int.Parse(value;
}
Это разные алгоритмы, -й накапливает сабстрочки, я все делаю в один проход. В данном простом случае, наверное алгоритм -я предпочтительнее. Но суть то в том что бы сравнивать ОДИН алгоритм и разные ЗАПИСИ. Переписать -я через мой подход?
это что-то новое , обычно спагетти называют как раз код, который тянется в линию, разветвляется и запутывается, как спагетти. Как раз там передают данные типа флажков, null-ов и "-1".спагетти - в первую очередь пошло с goto
и как раз код с большим кол-вом колбаков и начинает походить на код с goto
По ссылке всего 98 строк, я чего-то не понял?Мб обсчитался. Кода много, в глазах рябит.
Переписать -я через мой подход?А смысл? Чтобы было непонятно?
Это разные алгоритмы, -й накапливает сабстрочки, я все делаю в один проход.Возможно, но твой код недостаточно ясен, чтобы с одного взгляда определить, что он делает.
я все делаю в один проходзадача была как раз продемонстрировать подход на комбинации двух функций TryParse и IndexOf, а не реализовывать эту простую задачу оптимальным способом по читаемости или еще по чему.
Вообще, я пока не понимаю смысл происходящего: тобой пишется какой-то код без хорошей аргументации, почему он лучше. Хорошая аргументация, например, — почему надо писать, как ты предлагаешь, что и почему станет лучше.
А откуда такой странный values.Sum? Это в стандартной библиотеке такое?
А смысл? Чтобы было непонятно?нет , все останется так же понятно . Но код будет немного безопаснее, будет лучше рефакториться. Причем как формальный рефакторинг, так и с участием человеческого мозга
А последний разве работает?а что ему не работать?
если исправить пару мелких неточностей, то и компилируется, и суммирует
static IEnumerable<string> Split(string str)
{
var index = 0;
for (; ; )
{
var pos = str.IndexOf(' ', index);
if (pos == -1)
break;
yield return str.Substring(index, pos - index);
index = pos + 1;
}
if (index < str.Length)
yield return str.Substring(index);
}
static int Sum(string str)
{
return Split(str).Sum(value => Util.Parse(value ? 0;
}
class Util
{
static public int? Parse(string value)
{
int result;
if (int.TryParse(value, out result
return result;
return null;
}
}
Sum.
Если бы его не было, можно было бы сделать соответствующий Extension метод. У того же написана достаточно удобная библиотека хелперов, которые позволяют писать код проще.
в .NET Framework 3.5 входит Linq, который позволяет довольно удобно работать с коллекциями объектов: делать выборки, агрегировать и пр. В частности, есть и агрегатор Если бы его не было, можно было бы сделать соответствующий Extension метод. У того же написана достаточно удобная библиотека хелперов, которые позволяют писать код проще.
все останется так же понятнотвой код в этом треде по большей части ни фига непонятный
Хорошая аргументация, например, — почему надо писать, как ты предлагаешь, что и почему станет лучше.основной аргумент — результат поиска возвращается в качестве параметра лямбды, и это значение всегда "хорошее", а там где оно не имеет смысла, там его нет.
твой код в этом треде по большей части ни фига непонятныйок, давай по шагам, вот есть две записи одного алгоритма
Чем второй менее понятный?
Жесть. А они до конца не пошли, в том плане чтобы записи a.f(b) и f(a, b) были эквивалентны?
Оба жрут O(n^2) памяти. Или я уже туплю под вечер?
Пример продемонстрировал, что TryParse и IndexOf сочетать можно, но получается громоздко. Какие выводы надо сделать?тк нас интересует не конкретно TryParse и IndexOf, а стиль с делегатами
Оба жрут O(n^2) памяти. Или я уже туплю под вечер?.......... , но эта характеристика сейчас не рассматривается
Жесть. А они до конца не пошли, в том плане чтобы записи a.f(b) и f(a, b) были эквивалентны?Пока нет.
Лично мне не нравится, что происходит с C#. Слишком легко стало писать плохо. В долговременной перспективе это означает эффект C++/PHP про который еще Линус говорил в ответ на вопрос "Почему ядро линукса на C, а не на С++"
но эта характеристика сейчас не рассматриваетсяс учетом этой характеристики, такой код нельзя применять. Ведь, как мне поведал , каждый раз, когда мы пишем алгоритм со сложностью O(n^2 Бог убивает котенка.
ну тк через несколько лет C# выкинут и сделают новый чистый язык
тк нас интересует не конкретно TryParse и IndexOf, а стиль с делегатамииногда делегаты удобны. Например, в коде они тоже используются.
А сколько вы примерно времени тратите на изучение фишек новых версий языков, библиотек и т.п. - как тех, что нужно для текущих проектов, так и на перспективу, чтоб типа ценность на рынке труда не падала? Имхо это довольно скучно, ведь что-то концептуально новое бывает крайне редко.
Видимо, Б-га нет, потому что такого кода дофига и котят тоже немало. :\
Имхо это довольно скучно, ведь что-то концептуально новое бывает крайне редкоСогласен.
А в какой области часто возникает концептуально новое?
А сколько вы примерно времени тратите на изучение фишек новых версий языков, библиотек и т.п. - как тех, что нужно для текущих проектов, так и на перспективу, чтоб типа ценность на рынке труда не падала? Имхо это довольно скучно, ведь что-то концептуально новое бывает крайне редко.Могу ответить за себя: на данном этапе моей жизни на повышение своих навыков трачу порядка 15-20 часов в неделю + 40 часов работа, на которой то, что оказалось полезным, применяю.
Да, и надо отметить, что на C#/.NET жизнь не заканчивается. За последние полгода мне пришлось писать код примерно на 5 языках — C#, Java, Python, JavaScript, Sawzall.
Насчет же интереса — у меня он в основном проявляется в том, как бы сделать очередную задачу просто. Стараюсь бороться с детскими болезнями, когда для простых вещей я писал свой язык+интерпретатор или же декомпилятор+анализатор.
15-20 часов в неделю + 40 часов работа, на которой то, что оказалось полезным, применяю.ты как-то так отделил, ты на работе не читаешь что ли?
Как правило, я это делаю обычно с работы, но при этом занимаюсь не своим проектом. Поэтому и отделил от работы.
Ты действительно сейчас переизобрёл continuation-passing style.
Я понимаю, что оно выглядит прикольно и позволяет развлечь себя нетривиальным кодингом, напрячь моск и всё такое.
Но. Скачай Paul Graham's "On Lisp", и посмотри на страницу 273, где он показывает, как простая функция для реверсирования списка выглядит после CPS transform. Внимательно посмотри, попытайся понять, как оно работает. Я больше пятнадцати минут ффтыкал в эти восемь строчек, прежде чем вроде бы как понял, но забыл тут же как только потерял концентрацию, прям как с Y-combinator.
Это — логическое завершение того, что тебя сейчас так развлекает.
Подумай о том, что непопулярность лиспа довольно сильно определяется тем, что некоторые его конструкции тяжелы для понимания. Подумай о том, что даже убеждённый лиспофаг Грэхэм пишет: "A Lisp program can be transformed into a form called “continuation-passing style.” Programs which have undergone complete CPS conversion are impossible to read <..>".
Забей, короче. Этот путь не принесёт тебе ничего хорошего.
Мб обсчитался. Кода много, в глазах рябит.Если переходить на флуд, то есть вот такое мнение
Возможно, но твой код недостаточно ясен, чтобы с одного взгляда определить, что он делает.
“Один из наиболее трудных для понимания моментов в объектно-ориентированной программе связан с общим потоком управления. При хорошем проектировании в различных классах определяется множество небольших методов, и временами понять последовательность поведения системы бывает довольно сложно. Можно достаточно долго вглядываться в код, пытаясь понять, что же делается в программе. Особенную трудность это вызывает у тех, кто впервые сталкивается с объектным подходом. Диаграммы последовательности как раз и помогают разобраться в процессе поведения системы.”
М. Фаулер, “UML в кратком изложении”
И при всем при этом Фаулер проповедует использование объектно-ориентированного программирования. То что с первого взгляда код не понятный, это еще ни о чем не говорит. Да и смотреть надо под ReShaper-ом
Ухитряются что-то новое и придумывать и реализовывать.
static int Sum(string str)
{
var index = 0;
var sum = 0;
for (; ; )
{
var pos = str.IndexOf(' ', index);
var subString = pos == -1 ? str.Substring(index) : str.Substring(index, pos - index);
int parseResult;
if (int.TryParse(subString, out parseResult
sum += parseResult;
if (pos == -1)
break;
index = pos + 1;
}
return sum;
}
по моему с тех пор как в .NET появилось значение null у структур, эта проблема исчезла.
а если null-а не хватает чтобы выразить "вторую" ветку, то вместо передачи функций параметрами удобнее программировать на case-ах. В .NET-е сейчас я так понимаю ничего похожего нет, ну появится когда нибудь. Я имею ввиду хаскельное
data TryParse = Result Int | ErrorPosition Int
tryParse :: String -> TryParse
case tryParse x of
Result r => ...
ErrorPosition e => ...
вместо мутного
tryParse :: String -> (Int -> a) -> (Int -> a) -> a
по моему с тех пор как в .NET появилось значение null у структур, эта проблема исчезла.это не структуры, это классы с дженерик параметром. С таким же успехом можно сделать классы-обертки хоть с десятью выделенными значениями, через них можно много чего передать.
Ну вот например в сетевых технологиях вроде бы нет такого, что все фичи давно придуманы и опробованы, только не реализованы крупными вендорами.можно несколько примеров концептуально нового, что было реализовано в последние 5 лет, чего до этого не было описано в научных статьях?
Ухитряются что-то новое и придумывать и реализовывать.
Вот так еще проще, короче и понятнее, без всяких yield return, лямбд и встроенных сумматоров.так мне меньше нравится, т.к. надо вглядываться что именно делается.
надо смотреть не забыли ли учесть последний элемент, или первый элемент.
с Split и Sum сразу видно, что именно делается.
надо смотреть не забыли ли учесть последний элемент, или первый элемент.тут как раз все единообразно все в одном цикле, находим число, и суммируем. А у тебя почему-то правый концевой элемент спеециально обрабатывается
if (index < str.Length)
Почему только правый? почему только концевой?
Почему только правый? почему только концевой?потому что алгоритм разбора через indexOf всегда такой
у тебя же тоже самое
var subString = pos == -1 ? str.Substring(index) : str.Substring(index, pos - index);
var index = 0;
for (; ; )
{
var pos = str.IndexOf(' ', index);
if (pos == -1)
{
yield return str.Substring(index);
break;
}
yield return str.Substring(index, pos - index);
index = pos + 1;
}
а в программировании уже много лет как готовые прототипы есть всем фичам, и теперь микрософты с санами до этих фичей добираются
человеку нужно только, грубо говоря, запоминать новый синтаксис для записи того же самого, и в каких версиях он появился
тут как раз все единообразно все в одном цикле, находим число, и суммируем. А у тебя почему-то правый концевой элемент спеециально обрабатываетсякстати у тебя не обрабатывается ситуация, когда в конце строки есть лишний концевой пробел.
кстати у тебя не обрабатывается ситуация, когда в конце строки есть лишний концевой пробел.конечный результат полностью совпадает с твоим. У тебя почему-то пробел в конце строки отрезается на этапе Split-а. А у меня все отрезается в одном месте — на этапе TryParse-а.
Если уловие задачи изменится, например, для всех невалидных строчек надо кидать исключение:
для такой "1 2 3 "
и для таких
" 1 2 3", "1 2 3"
то у тебя придется менять два метода.
А сколько вы примерно времени тратите на изучение фишек новых версий языков, библиотек и т.п. - как тех, что нужно для текущих проектов, так и на перспективу, чтоб типа ценность на рынке труда не падала? Имхо это довольно скучно, ведь что-то концептуально новое бывает крайне редко.на новые фишки мало времени уходит
много времени уходит на изучение технологий
что такое "технология", как не ещё одна реализация известной идеи?
то у тебя придется менять два метода.менятся будет только split
что такое "технология", как не ещё одна реализация известной идеи?и реализацией какой идеи является технология Linux?
или технология html? или технология Flash? или технология Avi?
менятся будет только splitнапиши вариант, когда кидается исключения для строчек
"1 2 3"
"1qwe2 3"
"1 2 3"
это должно быть 1, 2, 3 или 1, ошибка, ошибка, 2. 3?
это должно быть 1, 2, 3 или 1, ошибка, ошибка, 2. 3?просто исключение new ApplicationException("can't conver to number")
не знаю такой технологии
Linux - ещё одно юникс-подобное ядро
> или технология html? или технология Flash? или технология Avi?
ещё один markup, ещё одна виртуальная машина со встроенными графическими примитивами , ещё один контейнер
человеку нужно только, грубо говоря, запоминать новый синтаксис для записи того же самого, и в каких версиях он появилсянеее, сейчас еще не так все хорошо. Сейчас главная задача не сильно убиться о те грабли, которые разбрасывает майкрософт.
просто исключение new ApplicationException("can't conver to number")это уже было
static int Sum(string str)
{
try
{
return str.Split(' ').Sum(value => int.Parse(value;
}
catch(FormatException exc)
{
throw new ApplicationException("can't convert to number", exc);
}
}
с твоей реализацией Split доя строки "1 2 3 " исключения не будет
если бы я пользовался твоей библиотекой, в которой был бы метод Sum, я бы достаточно сильно удивился, увидев, что она падает на строке "1 2 3 ".
а на " 1 2 3" она должна падать?
Да, про перечень граблей я забыл - но это наверное в любой технологической отрасли есть, вот и слишком привычно.
Кстати, майкросовт и сан далеко не все реализовало, а пользоваться чем-то сторонним не всегда удобно. Вот, например, я так и не нашел реализации — чтобы для расчетов можно было просто писать формулкки, не заморачиваясь, когда они пересчитываются, и пусть сами обновляются на экране (Dataflow
с твоей реализацией Split доя строки "1 2 3 " исключения не будетсо стандартной реализацией split-а будет, или если мою реализацию довести до стандартной, убрав последний if
А ёксель разве так не делает?
а на " 1 2 3" она должна падать?на мой взгляд, она должна принимать на вход "(\s*[-]?\d+)+\s*". Метод ДаркГрея поменяется слабо.
private static Regex regex = new Regex(@"(\s*[-]?(?<n>\d++\s*", RegexOptions.Compiled);
int Sum(string str)
{
var values = regex.Matches(str).Groups["n"];
return values.Sum(mc => int.Parse(mc.Value;
}
А как поменяется твой мегакод?
UPD: вторая версия кода, т.к. в предыдущий раз чуть-чуть налажал с regex-ом.
private static Regex validator = new Regex(@"(\s*([-]?\d++\s*", RegexOptions.Compiled);
private static Regex regex = new Regex(@"[-]?\d+", RegexOptions.Compiled);
private static int Sum(string str)
{
if (!validator.IsMatch(str
{
throw new ApplicationException("wrong input line");
}
var values = regex.Matches(str);
return values.OfType<Match>.Sum(mc => int.Parse(mc.Value;
}
А ёксель разве так не делает?да эксель это уже давно делает. Представь непонимание людей (они каждый день работают с экселям когда они заказывают программное обеспечение и им говорят, что оно будет реализовано на самой современной платформе, а потом выясняется, что простые (но их много) вычисления реализовано с большим количеством недочетов, а добавление новых требует не мало времени.
ну а как же там хвалёный activex или как там сейчас это называется (опять забыл)?
ещё один markup, ещё одна виртуальная машина со встроенными графическими примитивами , ещё один контейнертак можно еще проще все объяснять: еще один адаптер одной хрени в другую.
это же только в идеальном вымышленном мире: например, в мире математики, или в мире машины тьюринга(машины лиспа) - все очень просто, и можно обойтись одними идеями.
а технология - это в первую очередь компромисс между несколькими идеями, компромисс между идеями и ограничениями реальной жизни и т.д.
самое главное - что идеи не позволяют ничего сделать, они позволяют только что-то объяснить, но не сделать.
соответственно зная идею, но не имея или не зная технологий эту идею реализующих - можно быть крутым теоретиком, но не практиком, не человеком, который реально что-то делает и меняет мир.
ну а как же там хвалёный activex или как там сейчас это называется, опять забыл?ты это к тому, чтобы эксель встроить в приложение?
ну да
А как поменяется твой мегакод?примерно также
Во-вторых, гонять данные в эксель и обратно эта задача, наверное, даже сложнее, чем сами вычисления . Т.е. у нас данные в объектах или в реляционной базе, а в какой форме их переливать в эксель не совсем ясно.
кстати этот код работает?
примерно такжепоказать сможешь?
кстати этот код работает?2-я версия - да. Только что проверял.
private static Regex validator = new Regex(@"(\s*([-]?\d++\s*", RegexOptions.Compiled);регэкспы вроде как похожи. Одним регэкспом нельзя обойтись?
private static Regex regex = new Regex(@"([-]?\d+)", RegexOptions.Compiled);
Можно. Но у меня код обработки усложнился от этого.
меняют мир по-моему как раз разработчики этих технологий, а также те, кто не дожидаясь микрософтов что-то делает, а не те, кто вынужден ботать эти технологии, только чтоб сохранить квалификацию
меняют мир по-моему как раз разработчики этих технологий, а также те, кто не дожидаясь микрософтов что-то делает, а не те, кто вынужден ботать эти технологии, только чтоб сохранить квалификациюСкорее, разработчики технологий меняют возможности прикладных программистов менять мир.
Можно. Но у меня код обработки усложнился от этого.может это лично мои тркдности, потому что регэкспы не очень хорошо знаю, но по мне пусть лучше обработка чуть больше, чем следить за двумя регэкспами.
Согласен, но по-моему невесело как-то этим прикладным программистам приходится.
стандартная ситуация, когда один код отвечает за валидацию, другой - за обработку данных. Такое разделение упрощает логику и не имеет заметных недостатков. Самый яркий пример: xml, который валидируется по схеме, а затем обрабатывается совсем другими средствами, которые имеют гарантию, что входные данные корректны, а значит, можно все делать проще.
показать сможешь?могу конечно, но я думаю ты понимаешь, что многое там исчезнет, поскольку было завязано на использование IndexOf (условие задачи). Теперь мы ищем подстроки регэкспом.
Но у -я тоже бОльшая часть исчезает.
на мой взгляд, она должна принимать на вход "(\s*[-]?\d+)+\s*". Метод ДаркГрея поменяется слабо.имхо, с regex-ом сложно
вроде все на split-е можно сделать
упасть на любой ошибке
str.Split(' ').Sum(value => int.Parse(value
проигнорировать все ошибки
str.Split(' ').Sum(value => IntHlp.TryParse(value ? 0
проигнорировать все лишние разделители, но упасть на ошибках
str.Split(' ')
.Where(value => !value.IsNullOrEmpty
.Sum(value => int.Parse(value
проигнорировать лишние концевые разделители, но упасть на остальных ошибках
str.Split(' ')
.Trim(value => value.IsNullOrEmpty
.Sum(value => int.Parse(value
недостаток - неинформативность сообщений об ошибках
в твоём случае "неверная строка", и сиди ищи что там не так
решение лучше в этом смысле, там понятно, на в каком месте ошибка
а, ну ещё недостаток - дублирование части логики разбора
могут рассинхронизоваться эти два регекспа
Согласен, но по-моему невесело как-то этим прикладным программистам приходится.вот этим ребятам, по-моему, довольно весело.
Ряд прикладных программистов занимаются скушными вещами, но это не означает, что только ими. Кому не пофиг, занимается вещами, которые действительно меняют мир, а значит интересны.
разделение упрощает логику и не имеет заметных недостатков.Если придется отрабатывать числа с десятичной точкой, оба регэкспа изменятся, так? это не является недостатком?
> Такое разделение упрощает логику и не имеет заметных недостатков.это недостаток не разделения, а конкретно моего кода. Т.к. валидатор вполне может указывать, в каком месте у него ошибка. Более того, обычно так и делают.
недостаток - неинформативность сообщений об ошибках
в твоём случае "неверная строка", и сиди ищи что там не так
old-skool решение лучше в этом смысле, там понятно, на в каком месте ошибка
Ну вот мне кажется, что таким гораздо меньше нужно ботать способы сделать то же самое, но с другим синтаксисом и с новыми граблями.
Если придется отрабатывать числа с десятичной точкой, оба регэкспа изменятся, так? это не является недостатком?если меняется формат входных данных, то меняется код валидации. Вполне ожидаемо и не является проблемой — изменится совсем немного.
Ты уже написал свой код, который умеет такое парсить? Или уже слишком геморно это делать твоим методом?
Ну вот мне кажется, что таким гораздо меньше нужно ботать способы сделать то же самое, но с другим синтаксисом и с новыми граблями.поясни свою мысль. Не понял.
ну вот движущийся робот не за счёт переписывания кода с java на c# развивается, а наверное за счёт новых алгоритмов распознавания образов, принятия решений и т.п.
то есть нету ни у микрософта, ни у сана с айбиэм фреймворков для роботов вроде, люди начинают с идей и заканчивают прототипом
использование последних технологий (при условии, что выбирается не самая последняя, а самая подходящая на данный момент) и позволяет высвободить руки для своей конкретной задачи.
то есть нету ни у микрософта, ни у сана с айбиэм фреймворков для роботов вроде, люди начинают с идей и заканчивают прототипомMicrosoft Robotics Studio
Lego Mindstorms
сразу есть стандартные модули (типа — камера, инфракрасная камера, сустав, моторчик и пр. среда разработки, отладки, эмулятор.
Ты уже написал свой код, который умеет такое парсить? Или уже слишком геморно это делать твоим методом?Если смотреть твой код, то там уже нет ни IndexOf ни TryParse. Мой метод отличался только в способе использования этих функций. Теперь их нет, а значит и "моего" метода нет, код полностью совпадет с твоим.
т.е. если изначально ты понял задачу распознать "\d+([ ]\d)*", а затем условия уточнили и стало возможным как угодно добавлять пробелы, тебе придется переписать все с нуля? Заменив свой код на ДаркГреевский?
Ну вот мне кажется, что таким гораздо меньше нужно ботать способы сделать то же самое, но с другим синтаксисом и с новыми граблями.замечал, что многие зрелые проекты спотыкаются в развитии, т.к. развитие начинает сдерживаться недостатками в используемых технологиях.
например, C/C++ - ошибками с памятью,
динамические языки - из-за сложностью с мелким рефакторингом (например, метод переименовать
статические языки - из-за сложностью с крупным рефакторингом и из-за сложностью "с попробовать" (сложно реализовывать только часть)
соответственно, использование более новых технологий даже с новыми граблями позволяют этот барьер сдвинуть дальше.
Заменив свой код на ДаркГреевский?ты можешь запостить что общего и чем различается твой код и код ДакГрея?
int Sum(string str)
{
var values = str.Split;
return values.Sum(value => int.Parse(value;
}
:
private static Regex validator = new Regex(@"(\s*([-]?\d++\s*", RegexOptions.Compiled);
private static Regex regex = new Regex(@"[-]?\d+", RegexOptions.Compiled);
private static int Sum(string str)
{
if (!validator.IsMatch(str
{
throw new ApplicationException("wrong input line");
}
var values = regex.Matches(str);
return values.OfType<Match>.Sum(mc => int.Parse(mc.Value;
}
Основная логика та же, добавлено 6 строчек, изменено две. А у тебя?
то есть такие штуки, чтоб непрофессионал мог поиграться с тем, что профессионалы делают уже давно
разница в том, что в области робототехники этот передний край вроде как есть, а в "бухгалтерии", откуда растут примеры этого треда - скорее нет
по первому впечатлению, это далеко от переднего краяты серьезно или смеешься? Если небольшая группа, скажем 2-3 человека заходят сделать ту же змею, они чо, должны сами делать радиосвязь, моторчики, камеры? Или все-таки они возьмут по-максимуму стандартные части, а сделают только то, что отличается?
то есть такие штуки, чтоб непрофессионал мог поиграться с тем, что профессионалы делают уже давно
разница в том, что в области робототехники этот передний край вроде как есть, а в "бухгалтерии", откуда растут примеры этого треда - скорее нет
то есть такие штуки, чтоб непрофессионал мог поиграться с тем, что профессионалы делают уже давноа что профессионалы в роботехники уже делают?
и чем сегодня профессиональная роботехника отличается (по возможностям) от профессиональной автоматики?
static IEnumerable<string> Split(string str)
{
var index = 0;
for (; ; )
{
var pos = str.IndexOf(' ', index);
if (pos == -1)
break;
yield return str.Substring(index, pos - index);
index = pos + 1;
}
if (index < str.Length)
yield return str.Substring(index);
}
static int Sum(string str)
{
return Split(str).Sum(value => Util.Parse(value ? 0;
}
class Util
{
static public int? Parse(string value)
{
int result;
if (int.TryParse(value, out result
return result;
return null;
}
}
С кодом у него общее только
Sum
сделали змею, респект получили, всё
по первому впечатлению, это далеко от переднего краяи вот есть отличный пример кафедры оптимального управления на ВМиК. Там есть довольно много дедов, которые стоит "на переднем крае". Ну, они так думают. И поскольку они профессионалы, используют только самодельные средства.
то есть такие штуки, чтоб непрофессионал мог поиграться с тем, что профессионалы делают уже давно
разница в том, что в области робототехники этот передний край вроде как есть, а в "бухгалтерии", откуда растут примеры этого треда - скорее нет
В результате люди у них по три года тратят на то, чтобы сделать тележку, которая едет на свет. Из полезного — люди у них хоть паять учатся.
Случай реальный, коллега, который учился на этой кафедре, рассказывал о своем студенчестве/аспирантуре.
ну а как эта группа мир-то изменит?там на голове камера. Теперь японские военные/спецслужбы могут заглядывать за угол или даже в другое помещение. Всунут змеюке в рот патрон — совсем зверюга станет.
сделали змею, респект получили, всё
а деды эти были когда-то на переднем крае, и я думаю, им было сильно веселее, чем тем, кто змею сделал
код ДакГрея вота не код ДаркГрея? Не юли, плз.
ну МГУ я думаю не стоит приводить в пример - сильно гнилое заведениееще веселее моему соседу по подъезду. Но у него справка из психушки.
а деды эти были когда-то на переднем крае, и я думаю, им было сильно веселее, чем тем, кто змею сделал
МГУ гнилое заведение, потому что аргументы "зачем использовать новое и стандартное, если у нас есть самодельное старье" применяются везде.
там на голове камера. Теперь японские военные/спецслужбы могут заглядывать за угол или даже в другое помещение. Всунут змеюке в рот патрон — совсем зверюга станет.включаем фантазию.
Ночь. В окопе сидят бойцы и напряженно смотрят вперед, в сторону расположения врага — пойманный язык сообщил, что в пять утра начнется атака.
5:02 — никого нет.
5:03 — приползли 50 змеюк, каждая выстрелила по разу, больше никого в окопе нет. Только тележка с надписью МГУ ползет на свет.
5:04 — атака закончена, высота взята.
а это не кодэто ты вырвал из контекста. Это только часть кода, посмотри посты выше указанного тобой поста.
Не юли, плз.
Как раз ты выдираешь отдельные посты из треда, и делаешь какие-то выводы. А то с чего начинался тред не хочешь замечать.
это всё круто, но ведь пчолы с нанотехнологиями под брюхом прилетят быстрее
это всё круто, но ведь пчолы с нанотехнологиями под брюхом прилетят быстреефлудер, йо!
Окончательная работающая версия кода ДакГрея та, которую я привел.
Окончательная работающая версия кода ДакГрея та, которую я привел.Еще раз — Даркгреевский код, который я привел, если стереть отладочную печать, компилируется и работает. Этот код решает задачу суммирования чисел, разделенных пробелом.
Остальной код, который там приводился, нафиг не нужен.
а также те, кто не дожидаясь микрософтов что-то делает, а не те, кто вынужден ботать эти технологии, только чтоб сохранить квалификациюэто две крайности, и скорее всего как крайности - они обе проигрышные.
имхо, двигает тот, кто делает что-то свое и успевает при этом посмотреть какие уже стандартные вещи есть/появились, и умудряется свои кубики заменить на похожие стандартные.
я к тому, что кроме мейнстрима здесь есть (или должны быть) и более продвинутые разработки
мгушные деды ими не занимаются, ну и фиг с ними - в мгу вообще инженеров не готовят вроде как
Этот код решает задачу суммирования чисел, разделенных пробелом.Да, но это не полное условие задачи.
Если смотреть твой код, то там уже нет ни IndexOf ни TryParse.конечно, потому что я твердо считаю, что IndexOf в таких задачах подлежит обязательному заменению на итератор, а TryParse с out-параметром подлежит замене на функцию с одним результирующим значением - пусть сложным(например, в виде вспомогательной структуры но главное без out-ов.
конечно, потому что я твердо считаю, что IndexOf в таких задачах подлежит обязательному заменению на итератор
если ставить просто задачу суммирования, то это несомненно так. Мне удивляет, почему опытных программеров, так увлекла сама по себе задача суммирования чисел
TryParse с out-параметром подлежит замене на функцию с одним результирующим значением - пусть сложным(например, в виде вспомогательной структуры но главное без out-ов.Почему? Потому что out-параметры плохо сочитаются с лямбдами?
Почему? я так с ходу не могу придумать стоящего аргумента.потому что тогда есть один однородный результат, с которым проще проводить дальнейшие взаимодействия.
возьмем для примера вот такие TryParse:
int.TryParse(string, out int result)
и
такой
int? int.TryParse(string)
вместо них кстати мог быть TryParse, который еще возвращает причину ошибки
bool TryParse(string, out int result, out Exception exc)
TryParseResult TryParse(string)
class TryParse
{
public readonly int Result;
public readonly Exception Error;
public bool IsSuccess {get {return Error != null;}}
}
задача вывести ошибочные лексемы:
в одном случае
var items = str.Split(' ');
Console.WriteLine(items.Where(item => int.TryParse(item) == null).JoinToString(", ";
в другом:
var items = str.Split(' ');
Console.WriteLine(items.Where(item => {var result; return int.TryParse(item, out result);}).JoinToString(", ";
задача: вывести ошибочные лексемы и посчитать сумму на неошибочных
var items = str.Split(' ');
var parsedItems = items.Select(str => new{Source = str, Result = int.TryParse});
Console.Error.WriteLine(parsedItems
.Where(parsedItem => parsedItem.Result == null)
.Select(parsedItem=>parsedItem.Result)
.JoinToString(", ";
Console.WriteLine(parsedItems.Where(parsedItem => parsedItem.Result != null)
.Sum(parsedItem=>parsedItem.Result;
в другом
var items = str.Split(' ');
var parsedItems = items.Select(str =>{int result; bool isParsed = int.TryParse(str, out result);
return new{Source = str, Result = isParsed? (int?)result: (int?)null;}
);
Console.Error.WriteLine(parsedItems.Where(parsedItem => parsedItem.Result == null)
.Select(parsedItem=>parsedItem.Result).JoinToString(", ";
Console.WriteLine(parsedItems.Where(parsedItem => parsedItem.Result != null)
.Sum(parsedItem=>parsedItem.Result;
т.е. out-параметр почти всегда требует больше кода, чем без out-параметров
я к тому, что кроме мейнстрима здесь есть (или должны быть) и более продвинутые разработкитак все-таки у тебя есть ответы на эти вопросы
а что профессионалы в роботехники уже делают?
и чем сегодня профессиональная роботехника отличается (по возможностям) от профессиональной автоматики?
var items = str.Split(' ');имхо, так даже лучше читается
var parsedItems = items.Select(str =>{int result; bool isParsed = int.TryParse(str, out result);
return new{Source = str, Result = isParsed? (int?)result: (int?)null;}
);
Console.Error.WriteLine(parsedItems.Where(parsedItem => parsedItem.Result == null)
.Select(parsedItem=>parsedItem.Result).JoinToString(", ";
Console.WriteLine(parsedItems.Where(parsedItem => parsedItem.Result != null)
.Sum(parsedItem=>parsedItem.Result;
var parsedItems = items.Select(
str =>
{
int result;
return new
{
Source = str,
IsParsed = int.TryParse(str, out result
Result = result
};
});
Console.Error.WriteLine(parsedItems.Where(parsedItem => parsedItem.IsParsed == false)
.Select(parsedItem => parsedItem.Source).JoinToString(", ";
Console.WriteLine(parsedItems.Where(parsedItem => parsedItem.IsParsed)
.Sum(parsedItem => parsedItem.Result;
я че та так и не увидел особой разницы, кроме того, что в первом случае надо помнить, что null интерпретируем как то, что строка не распарсилась.
Console.Error.WriteLine(parsedItems.Where(parsedItem => parsedItem.Result == null)О! тут ты допустил прикольную опечатку вместо parsedItem.Result надо parsedItem.Source. Код даже в рантайме не сообщит об ошибке программиста.
.Select(parsedItem=>parsedItem.Result).JoinToString(", ";
Посмотрим на вариант с использованием моего метода
private interface IITem
{
string Source { get; }
bool IsParsed { get; }
int Result { get; }
}
private class ParsedItem : IITem
{
private readonly string str;
private readonly int result;
public ParsedItem(string str, int result)
{
this.str = str;
this.result = result;
}
public string Source
{
get { return str; }
}
public bool IsParsed
{
get { return true; }
}
public int Result
{
get { return result; }
}
}
private class NoParsedItem : IITem
{
private readonly string str;
public NoParsedItem(string str)
{
this.str = str;
}
public string Source
{
get { return str; }
}
public bool IsParsed
{
get { return false; }
}
public int Result
{
get
{
throw new ApplicationException;
}
}
}
static void Main
{
....
var parsedItems = items.Select(
str => IntEx.Parse<IITem>(
str,
i => new ParsedItem(str, i
=> new NoParsedItem(str)
);
Console.Error.WriteLine(parsedItems.Where(parsedItem => parsedItem.IsParsed == false)
.Select(parsedItem => parsedItem.Result).JoinToString(", ";
Console.WriteLine(parsedItems.Where(parsedItem => parsedItem.IsParsed)
.Sum(parsedItem => parsedItem.Result;
}
Да, он более громоздко смотрится. Но он падает с запланированным исключением!
Хо хо, а вы ж не в курсе, наверное, что String.Split вообще говоря оверлоаднутый и у него есть версия со StringSplitOptions?
Да, он более громоздко смотрится.Кстати, с Java-style анонимными классами, он бы был короче.
О, пока одни холиварами балуются, другие изучают современные технологии.
это две крайности, и скорее всего как крайности - они обе проигрышные.Золотые слова , услышали бы их наши архитекторы. Они сначала прошлись по одной крайности, теперь заканчиваю двух летний путь по второй крайности, и удивляются что опять как-то не так .
ну вот же, читал про роботов-разведчиков размером с пчелу
а если их ещё запрещённым химическим или биологическим оружием снабдить?
имхо, двигает тот, кто делает что-то свое и успевает при этом посмотреть какие уже стандартные вещи есть/появились, и умудряется свои кубики заменить на похожие стандартные.Майкрософт обычно делает не кубики, а довольно монолитную конструкцию.
1. Делать свою остову, у майкрософта брать "кубики", если удается их отделить.
2. Брать за основу майкрософт, ничего в ней не менять. Добовлять фичи строго придерживаясь подхода майкрософт.
3. Брать за основу майкрософт, пытаться некоторые "кубики" заменить своими.
У какого вариант вероятность, быть выигрышным, больше?
ну вот же, читал про роботов-разведчиков размером с пчелутакой же пиар как робот-змея.
я думаю, что робототехника - подраздел автоматикикак человек, который видел профессиональную массовую автоматику изнутри - могу сказать, что там обычно применяются все те же самые "бухгалтерские" технологии: C/C++, Dos, Windows, Java, .Net, Linux.
из нестандартного разве что видел QNX, embedded NT и технологии заточенные под инженеров (что-нибудь типа языка функциональных блоков)
соответственно, в профессиональной массовой роботехники скорее всего применяются все те же самые "бухгалтерские" технологии
Хо хо, а вы ж не в курсе, наверное, что String.Split вообще говоря оверлоаднутый и у него есть версия со StringSplitOptions?да, не в курсе.
меня больше интересовало показать, как бы я решал похожие задачи с разбором чего-либо (не обязательно строки, и не обязательно через родной split и обработкой результата
var parsedItems = items.Select(
str => IntEx.Parse(
str,
i =>
{
Func<int> func = => i;
return new { Source = str, IsParsed = true, ResultFunc = func };
},
=>
{
Func<int> func = => { throw new ApplicationException; };
return new { Source = str, IsParsed = false, ResultFunc = func };
}
);
Console.Error.WriteLine(parsedItems.Where(parsedItem => parsedItem.IsParsed == false)
.Select(parsedItem => parsedItem.ResultFunc.JoinToString(", ";
Console.WriteLine(parsedItems.Where(parsedItem => parsedItem.IsParsed)
.Sum(parsedItem => parsedItem.ResultFunc;
Т.е. получилось и безопасно и коротко .
я тут был не до конца прав, в случае TryParse эквивалентной записи нет. Такая записьНа самом деле эквивалентная запись есть (я как-то забыл про анонимные классы)
code:
int result = default(int);
IntEx.Parse(
"123",
i =>
{
result = i;
return true;
},
=>
{
result = default(int);
return false;
};
хуже, чем out параметром, приходится инициализировать переменную, да и переменных получается два i, result.
var parseResult = IntEx.Parse(
"123",
i => new {Result = i, IsParsed = true},
=> new {Result = default(int IsParsed = false}
;
public static Func<TResult> Sum5<TResult>(string str,
Func<int, TResult> successFunc, Func<TResult> failedFunc)
{
int sum = 0;
int toIndex = 0;
while (true)
{
var findController = Util.IndexOf(
str, " ", toIndex,
index =>
{
Action action = => toIndex = index + 1;
return new
{
FoundString = str.Substring(toIndex, index - toIndex
IsContinue = true,
BeforeContinueAction = action
};
},
=>
{
Action action = => { throw new ApplicationException; };
return new
{
FoundString = str.Substring(toIndex
IsContinue = false,
BeforeContinueAction = action
};
};
if (IntEx.Parse(
findController.FoundString,
i =>
{
sum += i;
return true;
},
=> false
== false)
{
return failedFunc;
}
if (findController.IsContinue == false)
{
break;
}
else
{
findController.BeforeContinueAction;
}
}
return => successFunc(sum);
}
Если не учитывать скобочки и пустые строчки, то он не сильно больше , но более устойчив к ошибкам.
задача: вывести ошибочные лексемы и посчитать сумму на неошибочныхВот решение, если идти до конца подходом, который упоминается в первом посте треда
code:
var items = str.Split(' ');
var parsedItems = items.Select(str => new{Source = str, Result = int.TryParse});
Console.Error.WriteLine(parsedItems
.Where(parsedItem => parsedItem.Result == null)
.Select(parsedItem=>parsedItem.Result)
.JoinToString(", ";
Console.WriteLine(parsedItems.Where(parsedItem => parsedItem.Result != null)
.Sum(parsedItem=>parsedItem.Result;
public static class StringHlp
{
public static string JoinToString(this IEnumerable<string> items, string separator)
{
return string.Join(separator, items.ToArray;
}
}
public static void Do
{
var items = "1q 2qwe 33".Split(' ');
var isFirst = true;
TryParse(items,
item => i => { },
item => =>
{
if (isFirst == false) Console.Error.Write(", ");
else isFirst = false;
Console.Error.Write(item);
});
Console.Error.WriteLine;
var sum = 0;
TryParse(items, item => i => sum += i, item => => { });
Console.WriteLine(sum);
}
private static void TryParse(IEnumerable<string> items,
Func<string, Action<int>> successFunc, Func<string, Action> failedFunc)
{
foreach (var item in items)
IntEx.Parse(item, successFunc(item failedFunc(item;
}
Какой код лучше читается?
И в каком сделаешь меньше опечаток?
В какой безопаснее вносить точечные изменения?
Вопрос: все эти финты с коллекциями, как память расходуют? т.е. если у нас IEnumerable<string> идет как stream из файла или и базы данных.
да всё говно, имхо
да всё говно, имхочё та мне тоже начинает так казаться
Вопрос: все эти финты с коллекциями, как память расходуют? т.е. если у нас IEnumerable<string> идет как stream из файла или и базы данных.вопрос не понят
IEnumerable<string> Split
Файл не заканчивается полностью в память, а читается последовательно.
Будут ли в памяти создаваться структуры, объем которых пропорционален объему текстового файла, при использовании твоего кода?
Одно место я точно вижу
items.ToArray
но это место не принципиально.
Будут ли в памяти создаваться структуры, объем которых пропорционален объему текстового файла, при использовании твоего кода?при yield-ах - память не будет жраться
ну не совсем с тем же, этим классам не будет хватать "стандартности", их придется придумывать заново каждый раз, и соответственно заново каждый раз их изучать при желании воспользоваться.
у меня тут такая идейка появилась - наврядли конешно у еня первого - клево бы было если б в "исчислении типов" был такой оператор "|". чтобы как-нибудь так:
class A {...};
class B {...};
(A|B) f {...}
A|B x = f;
if (A a = x) {...}
if (B b = x) {...}
ну вобщем идея понятна.
class A implements A_or_B - не предлагать, это другое, тут автор этих классов должен такой вариант использования предполагать.
или я отстал от жизни, и в C# нынче можно добавить классу интерфейсов "снаружи", ну как методов?
а я правильно понимаю, что yield-ы реализуются переносом фрейма в хип? или неужели там тред отдельный стоит?
у меня тут такая идейка появилась - наврядли конешно у еня первого - клево бы было если б в "исчислении типов" был такой оператор "|".в Eiffel такое есть. Большого счастья, как оказалось, не приносит.
зачем ты меня расстраиваешь а я так надеялся...
data AlgExpr = SimpleNode [Char] | UnaryNode [Char] AlgExpr | BinaryNode [Char] AlgExpr AlgExpr | EmptyNode
тогда (возврящаясь к нашим баранам) можно было бы TryParse определить как
int|TryParseError TryParse (...)
а пользоваться можно будет тремя способами - не задумываясь о проблемах:
int x = TryParse(...); // исключение если не запарсилось
немного задумываясь:
case (int x = TryParse(... { // ну или что-то подобное
...
} else {
...
}
и сильно задумываясь:
var res = TryParse(...);
case (int x = res) {
...
} else case (TryParseResult err = res) {
... // узнать из err в каком символе проблема и т.п.
}
По моему клёво придумал. Пойти что ли сделать свой .NET язык
а я правильно понимаю, что yield-ы реализуются переносом фрейма в хип?что понимается под фреймом?
локальные переменные, которые используются между yield-ов трансформируются в переменные теневого класса
> локальные переменные ...
ну дада, frame функции, обычно же он на стеке лежит, а тут значит в "теневом классе". блин клевая штука, и вполне простая, почему её раньше в каких-нибудь С++ах не придумали...
недавно кстати видел "итераторы" на чистых Сях. вот нашел, фтыкать Example, это конкретный угар =) кто-нибудь может разобраться чё там вообще? два стека на один тред, да?
недавно кстати видел "итераторы" на чистых Сях. вот нашел, фтыкать Example, это конкретный угар =) кто-нибудь может разобраться чё там вообще? два стека на один тред, да?почти.
резервируем место на стеке, и при переключение в итератор двигаем стек на зарезервированное место, а потом обратно.
Если все эти проблемы решать самым топорным путём, можно прийти к следующему. В сишарпе частный случай этого уже есть: Nullable<A> = A | *, где * - одноэлементный тип. Ничего не мешает опредленить дженерик Coproduct<A,B>, и операции с ними сделать какие ты написал.
мне вот давно интересно было, почему до сих пор компиляторы программный стек держат на "аппаратном", а не в хипе. неужели настолько медленнее? это раньше для работы со стеком были "специальные" инструкции, а сейчас то внутри давно уже risc, которому вообще без разницы хип или стек, всё кеши решают по сути. а само управление памятью в этом месте можно значительно упростить, ведь можно пользоваться тем фактом, что освобождаться будет по принципу стека.
бонусы же за это вполне себе ощутимые - бесконечный стек в мультитредной программе даже на 32-х битах. ну и просто принципиальная возможность иметь в программе эти стеки миллионами.
немного пообщавшись с boost-ом у меня укрепилось убеждение, что поддержка понятия на уровне самого языка намного лучше, чем попытки принести в язык то, чего в нем изначально не задумывалось, с помощью "библиотеки". ну если понятие системного уровня я имею в виду. я вот например даже не знаю как сделать, чтобы Coproduct<A,B> и Coproduct<B,A> было одно и то же...
эх мутно это всё, как обычно
Языки с алгебраическими типами и паттерн-матчингом спасут российскую демократию.
специальные инструкции короче
что за алгебраические типы?
это пример
а ну то есть в итераторе не может быть рекурсии, как собственно и с yield-ами.с yield-ами рекурсия может быть запросто
static IEnumerable<int> X(int max)
{
for (int i = 0; i < max; ++i)
{
yield return i;
foreach (int x in X(i
yield return x;
}
}
Console.WriteLine(X(5).Select(i => i.ToString.JoinToString(", ";
соответственно и на любой другой реализации итератора можно организовать рекурсию.
И с другой стороны: Nullable<> в сишарпе сделано исключительно на уровне библиотеки, а то что синтаксический сахар добавлен это мелочи.
а вот еще чего хотел спросить, а как в этом "теневом" классе control point хранится?
обычный int
И с другой стороны: Nullable<> в сишарпе сделано исключительно на уровне библиотеки, а то что синтаксический сахар добавлен это мелочи.Ну да, мелочи.
Если я правильно понимаю (хотя могу и ошибаться, в reference что-то не написано ничего интересного этот "неважный" синтаксический сахар обеспечивает в том числе и возможность сложить два нуллабл инта. У Nullable<T>, видишь ли, оператора "+" как бы нету. И конверсия к T тоже только explicit, причём понятно, зачем так — всё-таки складывая два int?, ты хочешь получить тоже int?, равный нуллу если один или оба операнда равны нуллу, а вовсе не эксепшен.
Без этого синтаксического сахара нуллаблы можно было бы сразу выкидывать на помойку. Если я всё правильно понимаю, конечно.
ну какая-нибудь специализация шаблонов всяко сложнее, ничего же пишут компиляторы. скорее всё таки именно никому это не нужно, эх жалко
брр, а как можно на "обычный int" передать управление?
брр, а как можно на "обычный int" передать управление?управление передается на следующий вызов итератора, а внутри это устроено как обычный автомат - где состояние кодируется как int, и на основе текущего состояния выбирается нужная ветка.
т.е. если полностью разбирать код, то получается следующее (псевдокод):
var iterator = Create;
for (;;)
{
iterator.MoveNext; //вот передача управления
}
void MoveNext
{
switch (state) //вот память о текущем control point-е
{
case 1:
....
state++;
break;
case 2:
....
state++;
break;
case 3:
...
state = 1;
break;
}
}
Ее можно совместить с возвращением результата через параметр
static void Main
{
var enumerable = new[] { "1", "2", "qwe", "sddd" };
Console.WriteLine(
Parse<int>(enumerable, item => item.Return, item => => { }).Sum
);
Console.WriteLine(
Parse<string>(enumerable, item => i => { }, item => => item.Return(item.Value.JoinToString(", ")
);
}
static IEnumerable<TResult> Parse<TResult>(IEnumerable<string> enumerable,
Func<IMiscellaniesItem<string, TResult>, Action<int>> successFunc,
Func<IMiscellaniesItem<string, TResult>, Action> failedAction)
{
return enumerable.AsMiscellanies.Select<TResult>(
item => IntEx.Parse(item.Value, successFunc(item failedAction(item;
}
Правда тип пока в C#-е не вы водиться, но хотя бы контролируется.
Оставить комментарий
6yrop
[C#]Методы типа string.IndexOf (находит подстроку в строке int.TryParse (преобразовывает строку в целое) могут успешно найти и вернуть результат, но могут и ничего не найти, и тогда придумывают всякие условности возвращать "-1" или null.
На мой взгляд, запись через делегаты
более логична. В такой сигнатуре есть все что нужно, и нет ничего лишнего! Из сигнатуры метода явно видно, что есть ситуация, когда число может не распарситься. У метода string.IndexOf этого не видно, и надо самому вспомнить про это и лезть в доку, смотреть как эта ситуация обрабатывается. У метода int.TryParse ситуация немного получше, но out параметр тоже нельзя назвать простым решением, кстати, этот метод появился только во второй версии. Да и условный оператор опять таки усложняет понимание кода
Здесь переменная result может использоваться в обоих ветках if-а, но во второй ветки она не имеет смысла, и компилятор это не отследит. Иногда просто перепутаешь true/false, которые возвращает TryParse, а для теста, по крайней мере, надо запустить прогу, а это не всегда удобно в момент написания.
На таком примитивном примере выгода мизерная, но, имхо, если привыкнуть к такому стилю, то код будет в целом надежнее.
P.S. да еще надо про пефоманс помнить, но это там где он критичен