Страницы

Поиск по вопросам

понедельник, 29 октября 2018 г.

StringBuilder vs. String.Concat, C# [дубликат]

На данный вопрос уже ответили: Быстродействие объединения строк 1 ответ Update: Мои тесты были неправильные. StringBuilder выигрывает даже при объединении 5 строк
Я сравнил производительность StringBuilder и String.Concat c разным количеством строк, учитывая время на создание объекта StringBuilder.
При объединении 5 строк String.Concat всегда быстрее, иногда в 10 раз
При объедении 10 строк String.Concat всегда быстрее, иногда в 10 раз
При объединении 20 строк String.Concat всегда быстрее, иногда в 10 раз
Если ли смысл использовать StringBuilder для объединения маленького количества строк? Вроде объект StringBuilder сам по себе отнимает больше ресурсов, чем 20 строк.
Код, который использовался для теста:
class Program { static void Main(string[] args) { const int countOfStrings = 20; string[] stringsToMerge = new string[countOfStrings];
for (int i = 0; i < countOfStrings; i++) { stringsToMerge[i] = "stringN" + i; }
Console.WriteLine("Count of strings:" + countOfStrings);
Stopwatch stopWatch = new Stopwatch(); TimeSpan ts; stopWatch.Start(); stopWatch.Stop();
stopWatch.Restart(); string s = stringsToMerge[0]; for (int i = 1; i < countOfStrings; i++) { s = string.Concat(s, stringsToMerge[i]); } stopWatch.Stop(); ts = stopWatch.Elapsed; Console.WriteLine("String.Concat ms:" + ts.TotalMilliseconds);
stopWatch.Restart(); StringBuilder stringBuilder = new StringBuilder(stringsToMerge[0]); for (int i = 1; i < countOfStrings; i++) { stringBuilder.Append(stringsToMerge[i]); } stopWatch.Stop(); ts = stopWatch.Elapsed; Console.WriteLine("StringBuilder ms:" + ts.TotalMilliseconds);
Console.ReadKey();
} }


Ответ

Я исправил ваш код. Во-первых, перед тестированием скорости, все методы нужно "прогреть". При первом вызове JIT-компилятор генерирует машинный код с IL и это занимает некоторое время. Во-вторых, не нужно тестировать одну итерацию, так как случайное событие в ОС может исказить результат. Во-третьих, вы передаете странное значение, в конструктор StringBuilder. При его использовании заведомо создается маленький размер буфера, который будет расширяться несколько раз. Для максимальной производительности, если есть возможность, вы должны задавать размер буфера, который не будет менятся.
И не забывайте запускать в Release, а не в Debug
В исправленном варианте (не трогал конструктор):
Count of strings:5 String.Concat ms:1097.4772 StringBuilder ms:1294.881
Count of strings:10 String.Concat ms:2848.4845 StringBuilder ms:1970.4477
Уже на 10 выигрывает StringBuilder
const int countOfStrings = 5; const int iterations = 10000000; string[] stringsToMerge = new string[countOfStrings];
for (int i = 0; i < countOfStrings; i++) { stringsToMerge[i] = "stringN" + i; }
// компилируем IL в машинный код string.Concat("123", "qwe"); var x = new StringBuilder(40); x.Append("123qwe");
Console.WriteLine("Count of strings:" + countOfStrings);
Stopwatch stopWatch = new Stopwatch(); TimeSpan ts; stopWatch.Start(); stopWatch.Stop();
stopWatch.Restart(); for (int iter = 0; iter < iterations; iter++) { string s = stringsToMerge[0]; for (int i = 1; i < countOfStrings; i++) { s = string.Concat(s, stringsToMerge[i]); } } stopWatch.Stop(); ts = stopWatch.Elapsed; Console.WriteLine("String.Concat ms:" + ts.TotalMilliseconds);
stopWatch.Restart(); for (int iter = 0; iter < iterations; iter++) { StringBuilder stringBuilder = new StringBuilder(stringsToMerge[0]); for (int i = 1; i < countOfStrings; i++) { stringBuilder.Append(stringsToMerge[i]); } } stopWatch.Stop(); ts = stopWatch.Elapsed; Console.WriteLine("StringBuilder ms:" + ts.TotalMilliseconds);
Если же я переделаю использование StringBuilder, то он выигрывает уже на 5 строках:
StringBuilder stringBuilder = new StringBuilder(100); for (int i = 0; i < countOfStrings; i++) { stringBuilder.Append(stringsToMerge[i]); }
Count of strings:5 String.Concat ms:1053.0082 StringBuilder ms:699.7725

Что означают символы $, {}, {0} в записи вывода строк?

Что означают символы: $, {}, {0} - в подобных записях вывода строк?
Console.WriteLine($"Имя: {name} Возраст: {age}"); Console.WriteLine("Выводится значение {0} ", count);


Ответ

Со знаком доллара - это интерполяция строк, которая появилась в C#6. $ указывает на то, что это самая строка будет той самой, куда можно подставить переменные напрямую, не заморачиваясь какой-нибудь конкатенацией или строкой составного формата (об этом ниже). То есть вместо записи:
Console.WriteLine("Имя: " + name + ", Возраст: " + age);
Можно записать
Console.WriteLine($"Имя: {name} Возраст: {age}");
где name и age - переменные со значениями, которые объявлены где-то выше в коде.
Фигурные скобки внутри нужны, чтобы отделить простые строки от действительно имен переменных. Иначе компилятор не смог бы понять где name является просто частью строки, а где подставляемая переменная.

Там где написано {0}, {1} и т.д. - это cтрока составного формата, где вместо {0}, {1} и т.д. подставляются значения переменных, которые перечислены через запятую после это строки. Пример из доков:
string name = "Fred"; String.Format("Name = {0}, dt = {1}", name, DateTime.Now);
Здесь Name = и , hours = — фиксированный текст. Элементы форматирования — это "{0}" c индексом 0, который соответствует объекту name, и "{1}" с индексом 1, который соответствует объекту DateTime.Now
Номер соответствует номеру переменной в перечислении name, DateTime.Now. То есть если расположить их так: DateTime.Now, name, то строка выше выведется так:
Name = 01.01.2017 10:10:00 , dt = Fred
вместо
Name = Fred , dt = 01.01.2017 10:10:00
Кроме того сами цифры в строке можно размещать в разные позиции, главное, чтобы они соответствовали номеру переменной в перечислении. Так, если написать
String.Format("{1}{0}Name =, dt = ", name, DateTime.Now);
то выведется:
01.01.2017 10:10:00FredName =, dt =

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

Вычисление квадранта, в котором находится точка двумерной координатной плоскости.

Здравствуйте, существует ли машинный способ определения квадранта, в котором находится точка с координатами x и y?

Наивное решение делает простой перебор вариантов:
if (x > 0 && y > 0)
printf("point (%d, %d) lies in the First quandrant
");
else if (x < 0 && y > 0)
printf("point (%d, %d) lies in the Second quandrant
");
else if (x < 0 && y < 0)
printf("point (%d, %d) lies in the Third quandrant
");
else if (x > 0 && y < 0)
printf("point (%d, %d) lies in the Fourth quandrant
");
else if (x == 0 && y == 0)
printf("point (%d, %d) lies at the origin
");

Вот мой более общий вариант (внимание: в моём варианте точка 0,0 координатной плоскости находится на северо-западе и является наименьшей, отсюда и несколько другое распределение номеров квадрантов, но суть та же) для нахождения квадранта распределения точки point от данной точки centerPoint вариант (для пограничных случаев я намеренно помещаю точки, лежащие на границах квадрантов, в один из этих квадрантов):
if (point.x > centerPoint.x) { if (point.y > centerPoint.y) { return KPClusterDistributionQuadrantFour; } else { return KPClusterDistributionQuadrantOne; } } else if (point.x < centerPoint.x) { if (point.y > centerPoint.y) { return KPClusterDistributionQuadrantThree; } else { return KPClusterDistributionQuadrantTwo; } } else { if (point.y > centerPoint.y) { return KPClusterDistributionQuadrantThree; } else if (point.y < centerPoint.y) { return KPClusterDistributionQuadrantTwo; } }
return KPClusterDistributionQuadrantNone;

Под машинным способом я главным образом подразумеваю использование битовых операций: мы видим, что:
квадрант I) x > 0, y > 0 => ++ квадрант II) x < 0, y > 0 => -+ квадрант III) x < 0, y < 0 => -- квадрант IV) x > 0, y < 0 => +-
...откуда, как подсказывает интуиция, можно было бы как-то схитрить, чтобы получилось:
+ ? + = 1 - ? + = 2 - ? - = 3 + ? - = 4
или в контексте моей координатной системы с иным распределением квадрантов:
+ ? - = 1 - ? - = 2 - ? + = 3 + ? + = 4
Вопрос в том, что может стоять за этим "?".
Буду рад любым советам. Интересуюсь этим вопросом больше для образования, хотя практика тоже обещает выиграть от этого, если такое решение возможно и существует.
Сам я также собираюсь посмотреть, как конкретно работают тангенсы и арктангенсы в С - возможно то, что они возвращают, мне тоже может как-то подойти.
Спасибо.

ОБНОВЛЕНО ПОЗЖЕ
Только что нашёл решение на SO, только теперь нужно попытаться его, как следует, понять: Optimizing quadrant selection
The fastest way in C/C++ it would be (((unsigned int)x >> 30) & 2) | ((unsigned int)y >> 31) (30/31 or 62/63, depending on size of int). This will give the quadrants in order 0, 2, 3, 1.
И решение относительно данного центра:
(((unsigned int)(x - center.x) >> 30) & 2) | ((unsigned int)(y-center.y) >> 31)
Буду признателен, если кто подскажет, что нужно изменить в этом решении, чтобы оно стало работать для точек x, y с типом double.

Комментарий по поводу принятого ответа
Оказалось, что всё-таки обычное решение с двойным if-else ветвлением работает быстрее, чем решение в принятом ответе (соотношение, которое я получаю достаточно стабильно: 160 к 180).

Вот окончательные версии, которые я сравнивал между собой (система координат инвертирована относительно оси y относительно декартовой):
Версия с обычным ветвлением
static inline KPClusterDistributionQuadrant KPClusterDistributionQuadrantForPointInsideMapRectBranching(MKMapRect mapRect, MKMapPoint point) { MKMapPoint centerPoint = (MKMapPoint){ mapRect.origin.x + mapRect.size.width / 2, mapRect.origin.y + mapRect.size.height / 2 };
if (point.x >= centerPoint.x) { if (point.y >= centerPoint.y) { return KPClusterDistributionQuadrantFour; } else { return KPClusterDistributionQuadrantOne; } } else { if (point.y >= centerPoint.y) { return KPClusterDistributionQuadrantThree; } else { return KPClusterDistributionQuadrantTwo; } } }
Вариант @paulgri
NS_INLINE int KPClusterDistributionQuadrantForPointInsideMapRect(MKMapRect mapRect, MKMapPoint point) { MKMapPoint centerPoint = (MKMapPoint){ mapRect.origin.x + mapRect.size.width / 2, mapRect.origin.y + mapRect.size.height / 2 };
double dx = point.x - centerPoint.x; double dy = point.y - centerPoint.y;
return ((*((long long *)&dy) >> 63) & 3) ^ ((*((long long *)&dx) >> 63) & 1); }
Решение со StackOverflow (адаптировано @avp для работы с double)
NS_INLINE int KPClusterDistributionQuadrantForPointInsideMapRect_avp(MKMapRect mapRect, MKMapPoint point) { MKMapPoint centerPoint = (MKMapPoint){ mapRect.origin.x + mapRect.size.width / 2, mapRect.origin.y + mapRect.size.height / 2 };
double dx = point.x - centerPoint.x; double dy = point.y - centerPoint.y;
return ((*((uint64_t *)&dx) >> 62) & 2) | (*((uint64_t *)&dy) >> 63); }
Еще одно решение, предложенное моим коллегой - оно более медленное, но все же рабочее, поэтому я добавляю его сюда для коллекции:
uint32_t x = ...; uint32_t y = ...;
char xsign = x >> 31 & 1; char ysign = y >> 31 & 1;
int quadrant = 1 + (xsign ^ ysign) + 2 * ysign;


Ответ

Если квадрант отыскивается относительно точки О(0,0), то можно обойтись битовыми операциями и манипулировать знаками чисел, зная, что сдвиг вправо является арифметическим (надеюсь, переменныне типа int?), например так (к размерам типов и пр. прошу не придираться, это набросок кода - только идея): n = ((y>>31)&3 ^ (x>>31)&1) + 1; Здесь +1 надо только для того, чтобы квадратны начинались с 1. Если относительно некоторой точки (x0,y0), то достаточно вместо x и y поставить разности. Как вариант - используйте тернарную операцию и обычные сравнения. UPD: одновременно написали )) Для типов с плавающей запятой битовые операции не применимы, используйте тернарную. UPD2: обратите внимание, это не тот же вариант, в моем варианте квадратны нумеруются правильно, по порядку 1,2,3,4. UPD3: Если x и y переменные типа double, то можно указатели на них привести к указателям на целочисленный тип так, чтобы знаковые разряды мантиссы оказались на месте знаковых разрядов целого и дальше все по той же схеме. Только посмотреть надо, где они у double. Приведение указателей на примитивные типы - фактически фиктивная операция, время не тратится ни на какие преобразования.

Какие языки программирования компилируются в исполняемый файл?

А именно чтобы эти языки были для Windows (exe) и Linux (elf). Плюс чтобы была работа с базовыми функциями (Сокеты, cmd(Windows), ...) Кроме c++


Ответ

Компиляция или интерпретация — не свойство самого языка. К практически любому языку можно построить компилятор, генерирующий нативный для данной операционки файл. Исключение составляют, пожалуй, лишь языки, в которых исходный текст ссылается на себя во время выполнения (например, если язык содержит goto на номер строки, вычисляемой во время выполнения — и то в этом случае можно построить таблицу переходов).
Другое дело, что для поддержки сложных фич (dynamic в C#, eval) вам может понадобиться доступность компилятора в системе во время выполнения.
Большой список можно посмотреть, например, тут
(Не все они поддерживают, например, работу с сокетами без внешних библиотек. Ну так C++ тоже работает с ними лишь через библиотеки операционной системы.)

Как выбрать элемент?

Как при клике на элемент из списка, добавить ему класс? При этом выбрать можно только 1 элемент


Ответ

Так как выбрать можно только один, то при клике есть текущий активный элемент и элемент по которому щелкнули. Нужно просто применить к ним toggleClass
$('li').on('click', function() { $('.active').add(this).toggleClass('active'); }); .active { background: red; }

  • El1
  • El2
  • El3

Если не нужно убирать выбранный, нужно проверить, что у элемента по которому щелкнули нет класса active
$('li').on('click', function() { if (this.classList.contains('active')) return; $('.active').add(this).toggleClass('active'); }); .active { background: red; }
  • El1
  • El2
  • El3

И последний вариант без использования jQuery
[].forEach.call(document.querySelectorAll('li'), function(li) { var active = document.getElementsByClassName('active'); li.addEventListener('click', function() { if (this === active[0]) this.classList.remove('active'); else { if (active[0]) active[0].classList.remove('active'); this.classList.add('active'); } }); }); .active { background: red; }
  • El1
  • El2
  • El3

И без использования jQuery без возможности снять выделение со всех
[].forEach.call(document.querySelectorAll('li'), function(li) { var active = document.getElementsByClassName('active'); li.addEventListener('click', function() { if (active[0]) active[0].classList.remove('active'); this.classList.add('active'); }); }); .active { background: red; }
  • El1
  • El2
  • El3

Как удалить из списка словари с повторяющимся полем?

У меня есть список словарей вроде такого:
[ {'id': 1, 'name': 'one'}, {'id': 2, 'name': 'two'}, {'id': 1, 'name': 'one'}, {'id': 3, 'name': 'three'} ]
Я хочу, чтобы остался список с уникальными id (неважно, что в остальных полях словаря). То есть, из примера выше должно получиться это:
[ {'id': 1, 'name': 'one'}, {'id': 2, 'name': 'two'}, {'id': 3, 'name': 'three'} ]


Ответ

Чтобы оставить в списке только словари с уникальным id (убрать повторения):
result = list({d['id']: d for d in list_of_dicts}.values())
Это линейный по времени и по памяти алгоритм.
Результат:
[{'id': 1, 'name': 'one'}, {'id': 2, 'name': 'two'}, {'id': 3, 'name': 'three'}]

Получить решение примера предоставленного в виде строки C#

Нужно разобрать выражение типа 1 + 1 (<Число><Оператор><Число>) и получить результат без использования операторов switch, if-else
Помогите с идеями, пожалуйста, не могу подступиться к проблеме!


Ответ

Собственно, @tym32167 уже дал 2 ответа на поставленный вопрос вперед меня, так что я подведу итог и добавлю еще варианты решения подобных задач

#0. Использование DataTable Expressions
DataTable - мощный .NET инструмент не только для хранения данных, но и для их обработки
При помощи метода DataTable.Compute(string expression, string filter) обычно производятся расчеты, исходя из данных, занесенных в DataTable. Однако часто к этому методу прибегают именно в Вашем случае
Так что организуем скромный вспомогательный класс:
public static class Calculator { // Создадим статический экземпляр DataTable, чтобы каждый раз не инициализировать его заново private static DataTable Table { get; } = new DataTable();
// Наш метод подсчета // Добавьте отлов ошибок по вкусу) public static double Calc(string Expression) => Convert.ToDouble(Table.Compute(Expression, string.Empty)); }
И будем использовать его подобным образом:
Console.WriteLine(Calculator.Calc("11 * 13")); // 143 Console.WriteLine(Calculator.Calc("2 + 2 * 2")); // 6 Console.WriteLine(Calculator.Calc("(13 % 11) / 4")); // 0.5

#1.0 Парсинг
Так как в рамках Вашей задачи точно известна модель <Число><Знак><Число>, как и предложил @tym32167 в своем втором ответе, можно использовать ручной парсинг выражения.
Перепишем наш класс:
public static class Calculator { // Определим функции для доступных операторов private static Dictionary> Operators { get; } = new Dictionary> { { '+', (a, b) => a + b }, { '-', (a, b) => a - b }, { '/', (a, b) => a / b }, { '%', (a, b) => a % b }, { '*', (a, b) => a * b } };
public static double Calc(string Expression) { // Очистим нашу строку от "мусора" в лице пробелов и прочих нехороших знаков Expression = string.Concat(Expression.Where(x => char.IsDigit(x) || Operators.ContainsKey(x) || x == ','));
try { int begin = 0; int end = 0;
// Заведем переменные для хранения наших чисел и оператора string a = string.Empty; string b = string.Empty; char op = '\0';
// Считаем переменную a из строки while (end < Expression.Length && (char.IsDigit(Expression[end]) || Expression[end] == ',')) end++; a = Expression.Substring(0, end);
// Если строка закончилась, значит нам отдали только одно число. Его же и вернем if (end == Expression.Length) return double.Parse(a);
// Считаем оператор op = Expression[end++];
begin = end;
// Считаем переменную b while (end < Expression.Length && (char.IsDigit(Expression[end]) || Expression[end] == ',')) end++; b = Expression.Substring(begin, end - begin);
// Достанем из словаря нужную нам функцию и запустим ее с двумя параметрами return Operators[op](double.Parse(a), double.Parse(b)); } catch { // Выражение некорректно и не может быть вычислено throw new EvaluateException(); } } }
Из пояснений к коду, надеюсь, логика понятна Используется как и в предыдущем случае:
Console.WriteLine(Calculator.Calc("1 + 7")); // 8 Console.WriteLine(Calculator.Calc("70 - 1")); // 69 Console.WriteLine(Calculator.Calc("70 % 3")); // 1 Console.WriteLine(Calculator.Calc("4 / 2")); // 2

#1.1 Парсинг
Процесс парсинга можно серьезно упростить, используя регулярные выражения Выглядеть это будет так:
public static class Calculator { // Определим функции для доступных операторов private static Dictionary> Operators { get; } = new Dictionary> { { "+", (a, b) => a + b }, { "-", (a, b) => a - b }, { "/", (a, b) => a / b }, { "%", (a, b) => a % b }, { "*", (a, b) => a * b } }; // Регулярное выражение // (-?\d+(?:\,\d+)?) - число типа double (может быть с запятой или без) // (.) - одиночный символ (наш оператор) private static Regex Regex { get; } = new Regex(@"(-?\d+(?:\,\d+)?)(.)(-?\d+(?:\,\d+)?)");
public static double Calc(string Expression) { // Очистим нашу строку от "мусора" в лице пробелов и прочих нехороших знаков Expression = string.Concat(Expression.Where(x => char.IsDigit(x) || Operators.ContainsKey(char.ToString(x)) || x == ','));
try { Match match = Regex.Match(Expression);
// Если все прошло успешно, то: // под индексом 1 лежит первое число // под индексом 2 - оператор // а под индексом 3 - второе число if (match.Success && match.Groups.Count == 4) // Достанем из словаря нужную нам функцию и запустим ее с двумя параметрами return Operators[match.Groups[2].Value](double.Parse(match.Groups[1].Value), double.Parse(match.Groups[3].Value));
// Выражение некорректно и не может быть вычислено throw new EvaluateException(); } catch { // Выражение некорректно и не может быть вычислено throw new EvaluateException(); } } }
Из пояснений к коду, надеюсь, логика понятна Используется как и в предыдущем случае:
Console.WriteLine(Calculator.Calc("1 + 7")); // 8 Console.WriteLine(Calculator.Calc("70 - 1")); // 69 Console.WriteLine(Calculator.Calc("70 % 3")); // 1 Console.WriteLine(Calculator.Calc("4 / 2")); // 2

#1.2 И снова парсинг (ANTLR4)
Спасибо большое @VladD за провокацию вдохновение на написание данного варианта решения проблемы)
Итак, подойдем к парсингу максимально серьезно и прибегнем к построению лексического и синтаксического анализатора. Для этого воспользуемся ANTLR4 (вещица весьма занятная и катастрофически удобная. Удивительно, что ранее я ее каким-то образом обходил стороной))
Для начала поставим необходимое расширение для VisualStudio Теперь в списке доступных шаблонов при добавлении нового файла в проект у нас появился раздел ANTLR. Выберем ANTLR4 Combined Grammar, который назовем Calculator.g4 Соберем проект Теперь у нас в папке obj/(Debug/Release) сгенерировались файлы CalculatorBaseVisitor.cs, CalculatorLexer.cs, CalculatorParser.cs, CalculatorVisitor.cs. Добавим их в проект по ссылке (Добавить как связь)
Первоначальная настройка произведена! Приступим непосредственно к созданию лексического анализатора
Грамматика (Calculator.g4) для нашего случая у меня получилась следующая (первый раз использую данную технологию, так что, возможно, написать можно было и лучше)
grammar Calculator;
/// Starting rule compilationUnit : expression+;
/// Parser Rules
// Обозначим наше выражение expression // Выше всего по приоритету идет выражение в скобках : LBRACKET expression RBRACKET # Brackets
// После идут single-функции | statement=(SIN | COS | ROUND) expression # Function
// Возведение в степень // заставляет парсер читать данное выражение справа налево | expression statement=POW expression # Pow
// Деление и умножение | expression statement=(MUL | DIV | MOD) expression # MulDiv
// Сложение и вычитание | expression statement=(SUB | ADD) expression # SubAdd
// Определенные нами константы | constant=(PI | E) # Constant
// Просто числовое значение (например: 3) | VAL # Val ;
/// Lexer Rules
// Фрагменты, которые мы потом будем использовать // для обозначения других лексических выражений fragment DIGIT : [0-9]; fragment NUMBER : DIGIT+; fragment DOT : '.'; fragment COMMA : ','; fragment SEPARATOR : (DOT | COMMA);
// Значения, используемые в парсере E : 'e'; PI : 'pi'; ADD : '+'; SUB : '-'; MUL : '*'; DIV : '/'; MOD : '%'; POW : '^'; COS : 'cos'; SIN : 'sin'; LBRACKET : '('; RBRACKET : ')'; ROUND : 'round'; VAL : NUMBER((SEPARATOR)NUMBER)?;
// WhiteSpace, который нам не очень-то и нужен) WS : (' '|'
'|'
'|'\t') -> skip;
Пересоберем проект. Теперь в наших автогенерирующихся файлах есть все необходимое для последующей работы
Обходить наше выражения для вычисления мы будем с помощью класса, реализующего паттерн Visitor
// Унаследуемся от базового "посетителя" // Укажем тип результата посещения - double public class ExpressionVisitor : CalculatorBaseVisitor { // Словарь с константами private static Dictionary Constants { get; } = new Dictionary { { "pi", Math.PI }, { "e", Math.E } };
// Словарь с функциями для одного выражения private static Dictionary> SingleOperators { get; } = new Dictionary> { { "sin", a => Math.Sin(a) }, { "cos", a => Math.Cos(a) }, { "round", a => Math.Round(a) } };
// Словарь с функциями для двух выражений private static Dictionary> DualOperators { get; } = new Dictionary> { { "+", (a, b) => a + b }, { "-", (a, b) => a - b }, { "/", (a, b) => a / b }, { "%", (a, b) => a % b }, { "*", (a, b) => a * b }, { "^", (a, b) => Math.Pow(a, b) } };
// Посещаем выражения public override double VisitBrackets([NotNull] CalculatorParser.BracketsContext Context) => Visit(Context.expression()); public override double VisitConstant([NotNull] CalculatorParser.ConstantContext Context) => Constants[Context.constant.Text]; public override double VisitVal([NotNull] CalculatorParser.ValContext Context) => double.Parse(Context.VAL().GetText().Replace('.', ',')); public override double VisitFunction([NotNull] CalculatorParser.FunctionContext Context) => ComputeOperation(Context.statement.Text, Context.expression()); public override double VisitPow([NotNull] CalculatorParser.PowContext Context) => ComputeOperation(Context.expression(0), Context.statement.Text, Context.expression(1)); public override double VisitMulDiv([NotNull] CalculatorParser.MulDivContext Context) => ComputeOperation(Context.expression(0), Context.statement.Text, Context.expression(1)); public override double VisitSubAdd([NotNull] CalculatorParser.SubAddContext Context) => ComputeOperation(Context.expression(0), Context.statement.Text, Context.expression(1));
// Вычисляем private double ComputeOperation(string Operation, CalculatorParser.ExpressionContext OperationContext) => SingleOperators.ContainsKey(Operation) ? SingleOperators[Operation](Visit(OperationContext)) : throw new EvaluateException(); private double ComputeOperation(CalculatorParser.ExpressionContext FirstOperation, string Operation, CalculatorParser.ExpressionContext SecondOperation) => DualOperators.ContainsKey(Operation) ? DualOperators[Operation](Visit(FirstOperation), Visit(SecondOperation)) : throw new EvaluateException(); }
Готово! Теперь при посещении лексических деревьев нужных нам выражений с помощью данного класса мы будем получать результат вычислений данных выражений)
Перепишем наш класс Calculator для взаимодействия с нашим "посетителем"
public static class Calculator { // Статический экземпляр "посетителя", чтобы каждый раз хоть его не создавать заново) private static ExpressionVisitor Visitor { get; } = new ExpressionVisitor();
// Парсим выражение и обходим полученное лексическое дерево public static double Calc(string Expression) => Visitor.Visit(new CalculatorParser(new CommonTokenStream(new CalculatorLexer(new AntlrInputStream(Expression.ToLower())))).compilationUnit()); }
Проверим:
Console.WriteLine(Calculator.Calc("2 + 2 * 2")); // 6 Console.WriteLine(Calculator.Calc("(2 + 2) * 2")); // 8 Console.WriteLine(Calculator.Calc("2 + 2 * 2^3^2")); // 1026 Console.WriteLine(Calculator.Calc("5 % 2 - 3")); // -2 Console.WriteLine(Calculator.Calc("sin(pi / 2) + cos(0) + round(0.9)")); // 3
Как видите, полученный калькулятор выполняет действия в правильной последовательности, а также может поддерживать абсолютно любые выражения и функции (которые мы, понятное дело, настроим))
И пусть данный вариант в ~40 раз медленнее метода #1.0, его преимущества в лице поддержки любого числа аргументов и всех вообразимых операторов делают сию версию подхода к разрешению подобных проблем очень и очень "вкусной")

#2.0 Компиляция выражения
Этот вариант будет самым массивным, ибо мы будем использовать доступ к экземплярам генератора и компилятора кода C# CSharpCodeProvider!
С помощью данного класса мы можем откомпилировать любой нужный нам код и поместить выходную сборку, скажем, в память
Итак. Логика наших действий:
Запихиваем наше выражение в return-statement некого метода некого класса (в качестве строки) Компилируем полученный код Полученную сборку загружаем в память Достаем из нее тип описанного нами класса Из него достаем описанный нами метод Запускаем его Отдаем результат
Выглядит сложновато. Но на деле все довольно просто! Вновь перепишем наш уже многострадальный класс Calculator
public static class Calculator { // Создадим экземпляр генератора и компилятора C#-кода private static Microsoft.CSharp.CSharpCodeProvider CodeProvider { get; } = new Microsoft.CSharp.CSharpCodeProvider(); // Зададим опции компиляции private static System.CodeDom.Compiler.CompilerParameters CompilerParameters { get; } = new System.CodeDom.Compiler.CompilerParameters() { // Нам не нужен исполняемый файл GenerateExecutable = false, // Выходной файл должен располагаться в памяти GenerateInMemory = true };
public static double Calc(string Expression) { try { // Откомпилируем наше выражение, которое будет располагаться внутри метода Calc класса Calculator System.CodeDom.Compiler.CompilerResults compilerResult = CodeProvider.CompileAssemblyFromSource(CompilerParameters, $"using System; static class Calculator {{ public static double Calc() {{ return {Expression}; }} }}"); // Получим сборку System.Reflection.Assembly assembly = compilerResult.CompiledAssembly; // Достанем из сборки нужный нам тип Calculator, из него - метод Calc и таки запустим его, приведя результат исполнения к double return (double)assembly.DefinedTypes.First(x => x.Name == "Calculator").GetMethods().First(x => x.Name == "Calc").Invoke(null, null); } catch { // Выражение некорректно и не может быть вычислено throw new EvaluateException(); } } }
Очевидным минусом такого подхода является время, которое уходит на компиляцию (на первый взгляд оно, конечно, может показаться не слишком значимым, однако оно все таки куда больше, чем время, требующееся для других методов)
Однако есть и хороший плюс: Вы можете использовать в выражении встроенные функции различных .NET библиотек, как то System.Math
Console.WriteLine(Calculator.Calc("Math.Sqrt(81) + Math.Sin(Math.PI / 2)")); // 10 Console.WriteLine(Calculator.Calc("Math.Log(8, 2)")); // 3 Console.WriteLine(Calculator.Calc("2 + 2 * Math.Log(4, 2)")); // 6 Console.WriteLine("70 % 3"); // 1

#2.1 Использование CSharp.Scripting
CSharp.Scripting - одно из детищ Roslyn, предоставляющее очень удобное API для построения и исполнения кода прямо в runtime!
(Необходимо поставить соответствующий NuGet-пакет!)
С использованием данного механизма наш класс Calculator ужмется до:
public static class Calculator { // Добавьте отлов ошибок на случай неверных выражений! public static double Calc(string Expression) => CSharpScript.EvaluateAsync(Expression).Result; }
Кратко, красиво и очень удобно, не так ли?
Однако стоит добавить бочку дегтя в эту ложку меда: данное API имеет схожие механизмы с теми, которые я использовал в примере #2.0, так что время, которое затрачивается на вычисления, до сих пор непомерно велико

Итоги
Чтобы выбрать из такого количества вариантов решение себе по душе, неплохо было бы иметь некую табличку со сравнительными характеристиками представленных методов... Собственно, ниже я ее и набросал (если я пропустил какой-то важный/интересный пункт - напишите, пожалуйста, в комментариях))
╔═════════════╦═════════╦═════════╦═════════╦═════════╦════════════╦════════════╗ ║ ║ #0 ║ #1.0 ║ #1.1 ║ #1.2 ║ #2.0 ║ #2.1 ║ ╠═════════════╬═════════╬═════════╬═════════╬═════════╬════════════╬════════════╣ ║ Время⁰ ║ 1370мс ║ 680мс ║ 1800мс ║ 28000мс ║ 42420100мс ║ 35457000мс ║ ╠═════════════╬═════════╬═════════╬═════════╬═════════╬════════════╬════════════╣ ║ Параметры¹ ║ [1..) ║ [1..2] ║ [2..2] ║ [1..) ║ [1..) ║ [1..) ║ ╠═════════════╬═════════╬═════════╬═════════╬═════════╬════════════╬════════════╣ ║ Сложность ║ 0.07 ║ 0.5 ║ 0.28 ║ 1 ║ 0.21 ║ 0.03 ║ ║ реализации² ║ ║ ║ ║ ║ ║ ║ ╠═════════════╬═════════╬═════════╬═════════╬═════════╬════════════╬════════════╣ ║ Набор ║ (+) (-) ║ (+) (-) ║ (+) (-) ║ Любые ║ Любые ║ Любые ║ ║ операторов³ ║ (*) (/) ║ (*) (/) ║ (*) (/) ║ ║ ║ ║ ║ ║ (%) ║ (%) ║ (%) ║ ║ ║ ║ ╚═════════════╩═════════╩═════════╩═════════╩═════════╩════════════╩════════════╝
0 - Среднее время расчета 1000000 выражений ("2 + 2") 1 - Количество числовых параметров, которые могут быть обработаны методом в одном выражении 2 - Относительная сложность реализации методов, рассчитанная на основе количества значимых операций 3 - Набор операторов, доступных внутри выражения
На основе таблицы видно, что абсолютным победителем по скорости исполнения стал метод #1.0, обогнав серебряного призера (#0) почти в 2 раза!
Легче всего в реализации (бесспорно) оказались методы #0 и #2.1, помимо этого они поддерживают нефиксированное число параметров внутри выражения
Использование регулярных выражений в методе #1.1 дало выигрыш в легкости реализации почти в 2 раза, однако скорость работы метода из-за этого ухудшилась почти в 3 раза!
Методы же #2.0 и #2.1 показали наихудшую скорость работы (почти в 62500 раз медленнее метода #1.0!). Однако их серьезным плюсом является то, что они поддерживают абсолютнo любые операторы (в том числе и тернарный) и функции, представленные стандартной .NET библиотекой!
Однако на фоне метода #1.2, который при тонкой настройке также способен поддерживать любые выражения и синтаксис, эти преимущества моментально меркнут

Надеюсь, мой ответ хоть немного помог Вам) Удачи в Ваших делах!

Указатель на тип char

Я как-то давно спрашивал по поводу указателей, разобрался, всем ответившим спасибо. Но сейчас мне пришлось столкнутся с типом char
int *a; char *b;
a = new int(10); b = "bla bla bla"; // Странно ведь мы записываем в адрес, а не в разыменованный указатель
cout << "a: " << *a << endl; // Выведет значение, а без * адрес (логично и понятно) cout << "b: " << b << endl; // Выведет значение всего того что мы засунули в "адрес" указателя, почему так, если приводить аналогию с int то почему тут не как там?
Хотелось бы понять, как работает указатель на тип char (хотелось бы увидеть аргументированные ответы, почему так различается, и что-то от себя как рекомендации). Шерстил интернет — по теме указателей в C++ ничего не нашел
P. S.: Прошу прощения, если эта тема всех достала или мое сообщение является дубликатом (есть темы похожие, но, вроде, это не то, что мне надо).


Ответ

Давайте рассмотрим предложения из вашего примера шаг за шагом.
В этом предложении
int *a;
вы объявили переменную a как указатель на объект с типом int
В этом предложении
char *b;
вы объявили переменную b как указатель на объект с типом char
В этом предложении
a = new int(10);
был создан объект в динамической памяти типа int, который был инициализирован значением 10.
В этом предложении
b = "bla bla bla";
в левой части выражения с оператором присваивания стоит переменна с типом char *. В правой части этого выражения используется строковый литерал "bla bla bla". Строковые литералы в C++ имеют типы константных символьных массивов.
(C++ Стандарт, 2.14.5 String literals)
8 Ordinary string literals and UTF-8 string literals are also referred to as narrow string literals. A narrow string literal has type “array of n const char”, where n is the size of the string as defined below, and has static storage duration (3.7).
Строковый литерал "bla bla bla" имеет тип const char [12]. В выражениях массивы неявно преобразуются к указателям на свой первый элемент.
Согласно стандарту C++ (4.2 Array-to-pointer conversion)
1 An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The result is a pointer to the first element of the array
Таким образом в приведенном предложении в правой части выражения с оператором присваивания используется значение типа const char *, которое указывает на первый символ строкового литерала "bla bla bla". То есть имеет место попытка указателю типа char * присвоить значение указателя типа const char *. Так как не существует неявного преобразования из типа указателя на константный объект в тип указателя на неконстантный объект, то компилятор должен выдать диагностическое сообщение.
Правильно было бы объявить переменную b следующим образом
const char *b;
Тогда вышеприведенное предложение с присваиванием было бы корректно, и переменной b был бы присвоен адрес первого символа строкового литерала, стоящего в правой части выражения от знака присваивания.
Данное предложение
b = "bla bla bla";
фактически, эквивалентно следующему предложению
b = &"bla bla bla"[0];
В этом предложении
cout << "a: " << *a << endl;
целочисленное значение, адресуемое указателем a выводится на консоль.
Было бы более корректно записать
cout << "*a: " << *a << endl; ^^^
В этом предложении
cout << "b: " << b << endl;
при условии, что компилятор каким-то образом сгенерировал объектный модуль, несмотря на ошибку, о которой я сказал выше, выведет на консоль строковый литерал, так как для указателей типа char * оператор operator << перегружен таким образом, что вместо значения самого указателя, он выводит содержимое памяти, адресуемое этим указателем, как строку.
Если вы хотите вывести на консоль именно значение самого указателя, то вам в таком случае следует написать либо
cout << "b: " << ( void * )b << endl;
либо
cout << "b: " << static_cast( b ) << endl;
А если переменная b была объявлена с квалификатором const, то
cout << "b: " << ( const void * )b << endl;
либо
cout << "b: " << static_cast( b ) << endl;

Установка кодировки в UTF-8 для текущего соединениния с MySQL [дубликат]

На данный вопрос уже ответили: Как настроить правильно кодировку для MySQL? 3 ответа Добрый день. Результат sql-запроса возвращается не в UTF-8 кодировке. Пытался установить кодировку с помощью функции mysql_set_charset('utf8',$db), но по все видимости функция не работает, при том, что MySQL версии 5.0.7. Как можно по другому задать кодировку соединения, но не используя SET NAMES? З.Ы. Когда работал с той же таблицей при помощи PDO, при установке кодировки: $db->exec('SET CHARACTER SET utf8') Поля возвращались в UTF-8


Ответ

Самый 100%ый код для 100%ого UTF-8 :D mysql_query("SET NAMES 'utf8'"); mysql_query("SET CHARACTER SET 'utf8'"); mysql_query("SET SESSION collation_connection = 'utf8_general_ci'");

Java 8 interface и abstract class

В Java 8 появилась возможность добавлять неабстрактные реализации методов в интерфейс, используя ключевое слово default, пример:
interface Formula { default double sqrt(int a) { return Math.sqrt(a); } }
В итоге, почти нет отличия между интерфейсом и абстрактным классом. Осталось только добавить объявлять переменные в интерфейсе и сделать возможность объявлять методы не только публичными и будет один в один...
Зачем такое сделали? Для чего? Каково применение такого подхода? В чем профит? Ведь специально интерфейсы и были сделаны для того, чтобы реализацию оставить на программиста, а там всего лишь сделать черновик, набросок. Объясните пожалуйста.


Ответ

Чтобы, например, можно было не париться с вещами такого рода, переопределяя их только там, где это даст выигрыш:
void add(X element);
default void addAll(Collection elements) { elements.forEach(this::add); }
кроме того, абстрактный класс сужает возможности наследника, а интерфейс позволяет их расширить: отнаследовавшись от абстрактного класса, нельзя не унести с ним всю его реализацию и нельзя взять еще какую-то. В принципе, описанное в последнем абзаце - шаг в сторону множественного наследования, которое во многих случаях будет указывать на корявую архитектуру, но, тем не менее, добавление такого функционала не вводит новые ограничения, а только расширяет возможности для применения.

Как определить основание системы счисления числа?

118924 в 10 системе счисления = 350214 в х системе счисления, как найти х? если можно то попродобнее


Ответ

Это ж всё брутфорс, это ж несерьезно :) На самом деле, конечно, перебор здесь вполне подходит, и можно дать ему границы сразу — по количеству цифр, по максимальной цифре. Но есть же и аналитический метод. 350214х = 11892410 Это означает, что 3x5 + 5x4 + 0x3 + 2x2 + 1x + 4 = 11892410 или 3x5 + 5x4 + 2x2 + x – 118920 = 0 Классический многочлен пятой степени. И теперь нужно просто решить полиномиальное уравнение. По основной теореме алгебры у него будет пять комплексных корней, нас, правда, интересует только действительный, хорошо бы положительный, и хорошо бы целый :) Из теоремы Абеля-Руффини известно, что аналитически мы такое уравнение не решим в общем случае, но я бы даже и пробовать не стал: на то придуманы численные методы, которых всяких есть многатыщ — выбрать можно по вкусу, начиная хоть с метода товарища Ньютона. Решаем, и получаем: x = 8 Хорошо и красиво. Ну можете еще добить преподавателя комплексными корнями, сказав, что это же число записывается точно так же в системе счисления с основанием (-7.07949 - 4.865i) :)

Квадратный корень из числа

Подскажите, пожалуйста, алгоритм нахождения квадратного корня из числа (не sqrt(a) и не pow(a, 0.5)), а итерациями, вручную. Ответ должен быть не целочисленным, а точным, типа float
Язык - желательно C.


Ответ

Можно попробовать метод Ньютона. По сути, чтобы найти корень из числа S, надо решить уравнение f(x) = 0, где

Подставляя эту функцию в формулу для итераций метода Ньютона, получаем

Я набросал работающую программу на Python, можете по ней ориентироваться:
#!/usr/bin/python import sys
s = float(sys.argv[1])
x = 1.0 while abs(x * x - s) > 0.00001: x = (x * x + s) / 2. / x print x

Случайно форкнул проект в GitHub, как теперь его удалить?

Случайно форкнул проект в GitHub. Проект x64dbg. Удалил у себя все файлы, но каталог master x64dbg остался.
Как от него избавиться? И желательно от истории тоже.


Ответ

Форк — это самостоятельный репозиторий на GitHub, он создается для того, чтобы вы могли продолжить работу над проектом, сохранили всю историю изменений до форка и могли делать пулл-реквесты.
Если вам нужно только получить последнюю версию проекта, то форк для этого не нужен. Можно клонировать «родительский» репозиторий, причём достаточно будет неполного (неглубокого) клонирования
Чтобы полностью удалить любой проект на GitHub (не обязательно форк):
Перейдите на страницу проекта (репозитория). В правой части экрана нажмите на вкладку Settings в виде шестерёнки.

В разделе Danger zone нажмите Delete this repository

В текстовое поле введите полное название вашего репозитория

Нажмите кнопку под текстовым полем для подтверждения.

Фреймворк PHP нужен ли? [закрыт]

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


Ответ

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

Как организовать скрипт “откуда и куда”?

Сначала выбираем первый пункт "Откуда" (остановка городского транспорта), далее выбираем "Куда" (тоже остановка городского транспорта), и скрипт показывает все возможные маршруты, на которых можно до этого пункта добраться (трамваи, троллейбусы, маршрутные такси...). И еще показывает примечание, в котором указаны маршруты, на которых можно добраться с пересадками.
Как организовать базу данных и выборку транспорта?


Ответ

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

В зависимости от масштабов проекта и желаемого результата могу предложить вам следующие варианты:
Поиск с помощью одно- и двунаправленного алгоритма Дейкстры (часто слабо не подходит для production'a, поскольку требует обхода большого числа ненужных вершин). Поиск с помощью одно- и двунаправленного алгоритма A* (или его вариаций типа Theta*). Обычно представляет собой лучшее решение для production'a по соотношению скорость / сложность реализации. Нужно твикать эвристику. Решения промышленного масштаба с препроцессингом, позволяющие находить ответ за миллисекунды. Рекомендую презентации и статьи Andrew Goldberg, который провел обзоры наиболее современных алгоритмов и эвристик для данной задачи, известных под аббревиатурами RE, HH, CH, TN, HL. Ссылки вы найдете в конце ответа. alt text http://i036.radikal.ru/1202/c7/eed9966758bd.png

Минус всех предложенных выше алгоритмов заключается в том, что они находят только один кратчайший путь.
А что делать, если таких путей нужно несколько (чтобы пользователь мог выбрать удобный для него)?
Можно использовать A* с различными эвристиками (практичное решение, сочетающее возможность настраивать эвристики с преимуществами исходного алгоритма). Воспользоваться алгоритмом Йена для нахождения k кратчайших путей на графе. Использовать любой альтернативный алгоритм поиска k кратчайших путей (обычно они менее известны, нежели алгоритм Йена), например, вот этот. Лично я не знаю алгоритмов, решающих задачу нахождения k кратчайших путей с массивным препроцессингом, однако, я не могу гарантировать, что на данный момент по этой теме нет толковых публикаций.

Презентации и дополнительные материалы по теме:
Andrew V. Goldberg - Routing Algorithms and Related Technology Andrew V. Goldberg - Hub Labeling Algorithm Andrew V. Goldberg - Shortest Paths in Road Networks Point-to-Point Shortest Path Algorithms with Preprocessing

Перевод списка строк в список чисел

a - список строк :['0', '0', '0', '0', '0', '0', '0', '0', '0', '0']
for el in a: el = int(el)
пытался таким способом преобразовать в числа, но в преобразует в рамках данного цикла


Ответ

Наиболее идиоматический и идеологически выверенный способ:
result = [int(item) for item in a]
По поводу вашего первого варианта: когда вы пишете for el in a, то каждый раз в цикле в el записывается ссылка на элемент списка. Но когда вы пишете el = int(el), то в переменную el просто записывается другая ссылка, сам элемент списка не меняется.
Как понять, что это именно ссылка, а не копия элемента? Вот пример, как при помощи вызова метода элемента списка меняется сам элемент:
>>> a = [[], [], []] >>> for el in a: el.append(1) >>> a [[1], [1], [1]]
По поводу вашего ответа, перебор со счетчиком (если он вам вдруг действительно понадобится) на Python правильнее (проще и приятнее, без всяких len вложенных в range) делать через enumerate:
for i, item in enumerate(a): a[i] = int(item)

Разница списков в Python [дубликат]

На данный вопрос уже ответили: Быстрое вычитание списков 3 ответа Имеется три списка: список1, список2 и список3.
Известно, что список1 > список2 (по количеству элементов), а список3 - пустой.
Также известно, что первые элементы список1 и список2 одинаковые (например, список1 = [Вася, Петя, Маша, Саша], а список2 = [Вася, Петя]).
Задача: заполнить список3 разностью первого и второго списков, т.е. на приведённом примере список3 = [Маша, Саша]


Ответ

Навскидку (т.к. set, элементы на выходе будут уникальными, т.е. без повторений) + не важно какие индексы у элементов, которые есть в обоих списках: list1 = [u'Вася', u'Петя', u'Маша', u'Саша'] list2 = [u'Вася', u'Петя'] list3=list(set(list1)-set(list2)) print list3 [u'Маша', u'Саша']

Глобальные переменные в Python: сохранить локальную переменную от вызова к вызову функции

У меня есть функция, которой необходимо сохранять значение от вызова к вызову, при этом это значение используется только в этой функции. Как правильно использовать глобальные переменные в Python? Я пробовал написать нечто подобное: someGlobalVar = 0
def incrimentGlobalVar() someGlobalVar = someGlobalVar + 1 Но данный код не работает. Может есть другие способы решения данной задачи?


Ответ

Есть несколько способов реализовать подобное поведение.
Глобальные переменные
Первое, что может прийти в голову, это использовать глобальные переменные. Важно учитывать то, что глобальные переменные доступы на чтение
def func1(): print(x)
x = 10 func1() # 10
но простое использование на запись не разрешается:
def func2(): y = 20 # создаёт локальную переменную, а не изменяет глобальную
y = 10 func2() print(y) # 10
Более того, при попытке обратиться к переменной сначала на чтение, потом на запись, мы получим ошибку:
def func3(): print(z) z = 20
z = 10 func3() # UnboundLocalError: local variable 'z' referenced before assignment
Это происходит из-за того, что использование присваивания переменной z обозначает её, как локальную (как в случае 2). Попытка вывести значение локальной переменной, у которой ещё не задано значение, как раз и порождает возникновение этой ошибки.
Аналогичный пример как раз приведён в вашем вопросе. Там тоже переменная someGlobalVar определяется, как локальная, потому что выполняется присваивание. Так как в этом присваивании используется сначала чтение значения ещё не инициализированной переменной someGlobalVar, мы получаем ту же ошибку.

Для того, чтобы этот пример работал, необходимо предварительно пометить переменную, как global
def func4(): global w print(w) w = 20
w = 10 func4() # 10 print(w) # 20
Аналогично будет работать и в вашем случае.

Использование поля функции
Второй способ, который может прийти в голову, это использование объекта функции для хранения состояния функции.
def func5(): if not hasattr(func5, '_state'): # инициализация значения func5._state = 0 print(func5._state) func5._state = func5._state + 1
# до первого вызова функции значение не установлено # print(func5._state) # AttributeError: 'function' object has no attribute '_state' func5() # 0 print(func5._state) # 1
В этом способе удобно то, что значение ассоциировано с самой функцией.
Стоит быть осторожным, давая имена подобным полям функции, так как в Python 2 у функции есть стандартные поля с названиями, не начинающимися с двух подчёркиваний, например, func_closure, func_code и т.п. Все они начинаются с func_, поэтому главное не использовать этот префикс и не начинать название поля с __, в остальных случаях шанс коллизии имён практически равен нулю.

Использование класса с поведением функции
Третий способ заключается в создании класса с поведением функции. Это наиболее удобный и безопасный, по моему мнению, способ реализации подобного поведения. Просто создайте класс и перегрузите его метод __call__
class FuncCreator: def __init__(self, start_state): self.state = start_state
def __call__(self): print(self.state) self.state += 1
func6 = FuncCreator(0) print(func6.state) # 0 func6() # 0 print(func6.state) # 1
Это увеличивает объём кода, но добавляет удобств от использования функциональности класса.

Использование изменяемого объекта, как значение по умолчанию для параметра
Четвёртый способ заключается в том, чтобы создать функцию, у которой будет необязательный параметр, использующий изменяемое значение в качестве состояния:
def func7(state=[]): if not state: state.append(0) print(state[0]) state[0] += 1
func7() # 0 func7() # 1
В качестве объекта состояния можно использовать любой изменяемый объект. Это использует то, что все значения по умолчанию присваиваются один раз.

Использование декоратора, выполняющего необходимые вычисления
Если вернуться к исходному примеру, то для подсчёта числа вызовов функции будет также может быть удобно использовать декораторы. Это позволит в том числе и переиспользовать код.
Для Python 3 код может выглядеть, например, так:
from functools import wraps
def call_count(func): count = 0 @wraps(func) def wrapper(*args, **kwargs): nonlocal count count += 1 func(*args, **kwargs) print(count) return wrapper
В Python 2 нет nonlocal, но можно использовать изменяемые переменные:
from functools import wraps
def call_count(func): count = [0] @wraps(func) def wrapper(*args, **kwargs): count[0] += 1 func(*args, **kwargs) print(count[0]) return wrapper
Использоваться это будет следующим образом:
@call_count def f(): pass
f() # 1 f() # 2
При желании вы можете скомбинировать этот способ с каким-нибудь из описанных ранее.

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

Формат даты в js

У меня есть пример кода: $("#curday").click(function () { var newdate; date = new Date(); newdate = date.getDate() + '.' + date.getMonth() + '.' + date.getFullYear(); $("#datepicker_down").val(newdate); }); Но у меня с ним есть проблемы. У месяца вывод начинается с нуля, то есть я сейчас имею 7-й месяц, а не 8-й, как это подправить? Формат вывода даты получается такой: 20.7.2012, а хочется получить вот такой: 20.07.2012, то есть чтобы если у числа и месяца если 1 цифра, то впереди автоматом дописывался ноль. Прошу помочь в этих нюансах. Заранее спасибо.


Ответ

Я бы посоветовал не ломать голову, а подключить библиотеку datejs Тогда пожно написать $("#datepicker_down").val( (new Date()).toString('dd.MM.yyyy') );

Не хочу использовать функцию for еще несколько раз!

static void Main() { double theta; //угол в радианах for (theta = 0.1; theta <= 1.0; theta = theta + 0.1) { Console.WriteLine("Синус угла {0} равен {1}", theta, Math.Round(Math.Sin(theta),2)); Console.WriteLine("Косинус угла {0} равен {1}", theta, Math.Round(Math.Cos(theta),2)); Console.WriteLine("Тангенс угла {0} равен {1}", theta, Math.Round(Math.Tan(theta),2)); } }
Здравствуйте, уважаемые. Сверху код вычисляет синус косинус и тангенс теты. На консоль выводится ответ такого типа (примерно):
Синус.... Косинус... Тангенс... Синус.... Косинус.... Тангенс.... ...........
А мне нужен ответ типа:
Синус.... Синус.... Синус.... ....... Косинус.... косинус.... Косинус.... ....... Тангенс.... Тангенс.... Тангенс.... .......
Я могу использовать еще два раза функцию for но мне кажется что это не правильно. Есть идеи как сделать это без нубских копирований? Думаю в языке есть методы чтобы использовать функцию несколько раз без лишней писанины! Но я не знаю! Буду рад любым ответам!


Ответ

Решение в лоб:
double theta; //угол в радианах for (int foo = 0; foo < 3; foo++) { for (theta = 0.1; theta <= 1.0; theta = theta + 0.1) { switch (foo) { case 0: Console.WriteLine("Синус угла {0} равен {1}", theta, Math.Round(Math.Sin(theta), 2)); break; case 1: Console.WriteLine("Косинус угла {0} равен {1}", theta, Math.Round(Math.Cos(theta), 2)); break; case 2: Console.WriteLine("Тангенс угла {0} равен {1}", theta, Math.Round(Math.Tan(theta), 2)); break; } } }

Вариация на тему лямбд:
Func, int> solve = (string funcName, Func func) => { for (double theta = 0.1; theta <= 1.0; theta = theta + 0.1) Console.WriteLine(String.Format("{0} угла {1} равен {2}", funcName, theta, Math.Round(func(theta), 2))); return 0; };
solve("Синус", Math.Sin); solve("Косинус", Math.Cos); solve("Тангенс", Math.Tan);

if \ else vs. switch \ case в C#

Что лучше использовать: if\else или switch\case?
int a = 3;
if (a == 1) { ... } else if (a == 2) { ... } else { ... }
switch(a) { case 1: ... break;
case 2: ... break;
default: ... break; }
Какая из этих конструкций работает быстрее? Почему? Когда лучше использовать то или другое?


Ответ

Оба условных оператора работают с одинаковой скоростью. Так как на уровне машинных команд они преобразуются в одни и те же инструкции.
Выбирать имеет смысл только по вкусу и по задаче.
switch может работать только с одной переменной. У if таких ограничений нет.
На мой взгляд, язык C# слишком высокоуровневый для такого рода оптимизаций.
Пишите читаемый код ;)

Стоит ли мне переходить с Python и Ruby на С#, в моем случае [закрыт]

Возможно конечно вопрос покажется глупым) Дело в том, что я убежденный пользователь Windows. C этой системой я уже 9 лет. И телефон у меня на Windows Phone. Для меня это самая удобная система, так уж получилось. Увлекаясь веб-разработкой, ранее для себя я выбрал питон и руби. Очень уж их все хвалят, вот и я решил попробовать. В целом мне нравится разработка на этих языках. Но сейчас я подумываю постепенно сместиться с веб-направления на мобильную разработку, и начать разрабатывать именно под мобильные Windows-системы. Язык C# мне нравится не меньше, чем вышеперечисленные языки. Если стану разрабатывать на .NET, то буду использовать одну технологию для обоих направлений (веб и mobile), что в принципе удобно. Для некоторых проектов на Питоне, а тем более на Руби, периодически приходится поднимать и настраивать виртуальные машины, что, скажу прямо, мне не очень удобно. В общем, хочу освоить "универсальную" технологию, которая бы мне идеально подошла P.S. Прошу не минусовать, никого не хотел обидеть и разжигать холивар тоже не планировал. Спрашиваю исключительно для себя


Ответ

Очень серьезное преимущество C# (а вместе с ним и .NET) кроется в том, что Microsoft выстроила вокруг всего этого очень ветвистую и большую экосистему, в которой можно вполне неплохо суествовать, будучи специалистом только лишь в технологиях, развиваемых Microsoft. Тот же самый C#, как правильно было замечено выше, позволяет писать и под десктоп (а Windows, на минуточку, - это 90% рынка), и для web, и для мобильных платформ (хоть тут, конечно, все туманно и зыбко - уверенности в светлом будущем Windows Phone и иже с ним нету) Собственно, под экостистемой я пдразумевал не только языки, фреймворки, SDK, огромные библиотеки классов на все случаи жизни, СУБД и среду разработки, но еще и всеобъемлющие системы документации, MSDN, всяческие видеопорталы вроде TechDays. Все это довольно давно создано, местами даже активно развивается и предоставляет широкий простор для развития, так что аргументы в пользу C#, думаю, вполне весомы. Чем может похвастаться Ruby/Python я, пожалуй, сказать не смогу - но на этот вопрос вы, полагаю, сможете ответить себе сами

Меняют ли состояние программы операции ветвления?

Многие операции меняют состояние программы через присваивание, приведение и т.д. Меняют ли состояние программы операции ветвления (условные операторы)? Или они просто переводят, в зависимости от некоторых условий, в одну из частей общего состояния?
Я так пониманию состояние программы это вся совокупность вычисляемых и/или используемых значений, потенциально изменчивых и/или постоянных в данный момент работающей программы. Могу конечно ошибаться.


Ответ

Текст программы лучше всего представить себе в виде набора пересекающихся дорог, а состояние выполняющего эту программу процесса — как машину, едущую по этим дорогам.
При этом ветвлениям соответствуют развилки дорог, циклам — круговое движение, и т. д. Любая операция есть продвижение машины по дороге, ветвление — выбор одной из дорог на развилке и продвижение по выбранной дороге.
Таким образом, ветвление не есть состояние, это лишь свойство «дорожной сети», её форма. А вот прохождение программой ветвления, как и любая другая операция, изменяет положение машины на дороге, то есть, состояние программы.

Напишите самое простое решение задачи 'Объединить два массива чередуя их элементы'

Как-то давно наткнулся в нете, на одну из задач которую возможно задать при собеседовании на место «Front-End Web Developer». Так вот ее условие:

Как я понимаю объединяющиеся массивы могут быть разной длины, поэтому нужно написать универсальную функцию, которая сможет вернуть результат двух массивов разной длинны.
let num = [1,2,3,4]; let str = ['a','b','c']; function sum(a,b) { let result = []; for (let i = 0; i < Math.max(b.length, a.length); i++){ result = result.concat(a[i]).concat(b[i]) } console.log(result) return result; } sum(num, str);
У меня получилось что у второго объединяющегося массива последний элемент может быть 'undefined'.
Как можно было бы решить по другому и интересней?
Правильный ответ получит тот у кого решение будет самым коротким и без 'undefined' как у меня. Чтобы увидеть самый 'простой' ответ, вопрос будет закрыт в 15:00 пятница, 6 апреля 2018 г. (GMT+1).Так как ответы увеличиваются с каждым днем, вопрос закроется в 15:00 понедельник, 9 апреля 2018 г. (GMT+1).


Ответ

вариант решения
let a = [1,2,3,4]; let b = ['a','b','c','d','e','f']; let s = Math.max(a.length, b.length)*2; let d = [a,b]; let r = []; for(i=0;i вторая ревизия, укоротил код заменой for на while, и math.floor на формулу
let a = [1,2,3,4]; let b = ['a','b','c','d','e','f']; let s = Math.max(a.length, b.length)*2, d = [a,b], r = [], v, i=-1; while(s-i++){ v = d[i%2][(i-i%2)/2]; // или d[i%2][~~(i/2)] if(v != undefined) r.push(v); } console.log(r)
по заявкам, для произвольного числа массивов.
const merge = (...d) => { let c = d.length, i = -1, v, r = [], s = Math.max(...d.map(x => x.length))*c; while(s-i++){ (v = d[i%c][~~(i/c)]) != undefined ? r.push(v):0; } return r; }; console.log( merge(['a','b'], [1,2,3], ['а','б','в','г']) )

Определение факта пересечения 3D треугольников

Есть 2 треугольника заданные тремя пространственными координатами (x,y,z) Допустим у нас есть подозрение по их пересечению треугольников (образующие кубы пересекаются).
Вопрос: как определить факт пересечения этих треугольников. Поясню. Мне не нужно знать в каком отрезке они пересекаются, и даже не нужно знать одну из точек пересечения. Меня интересует "быстрый" алгоритм поиска факта пересечения, т.е. true или false
З.Ы.: Искал в интернете, есть алгоритмы нахождения пересечения, а факта нет. И существуют ли вообще упращенные алгоритмы?
З.Ы.: Кое что нашёл. Есть сайт RealTimeRendering, Там есть метод Fast Triangle-Triangle Intersection test by Tomas Möller. Пока изучаю его. Подозреваю, что есть более быстрые алгоритмы.


Ответ

После поисков по просторам итернетов я нашел оптимальный способ описанный Томасом Моллером. Написал код под C# для данного алгоритма.
public bool PointInTriangle2D(float[][] t, float[] p) { bool inside = false; int j = 2; // = 3 - 1 for (int i = 0; i < 3; i++) { if ((t[i][1] < p[1] && t[j][1] >= p[1] || t[j][1] < p[1] && t[i][1] >= p[1]) && (t[i][0] + (p[1] - t[i][1]) / (t[j][1] - t[i][1]) * (t[j][0] - t[i][0]) < p[0])) inside = !inside; j = i; } return inside; }
public bool Moller1997b(Vertex[] V0, Vertex[] V1) { return Moller1997b(new Vertex[2][] { V0, V1 }); }
public bool Moller1997b(Vertex[][] V) { float[][] dv = new float[2][]; int[][] sign = new int[2][]; float[][] pv = new float[2][]; float[][] t = new float[2][]; float[][] triange2D = new float[3][]; float[] point2D = new float[2]; for (int j = 0; j < 3; ++j) triange2D[j] = new float[2]; for (int j = 0; j < 2; ++j) { dv[j] = new float[3]; sign[j] = new int[3]; pv[j] = new float[3]; t[j] = new float[2]; }
//Находим вектор-нормаль ко второму треугольнику Vertex N1 = (V[1][1] - V[1][0]).VectorProduct(V[1][2] - V[1][0]); //и коэфициент плоскости второго треугольника float d1 = -N1.ScalarProduct(V[1][0]); //Уровнение плоскости второго треугольника будет выглядеть //π2 : N2*X+d2=0, где X-любая точка плоскости (одна из точек v2) //Но нам это в данной задаче не важно //Проверяем с какой стороны плоскости лежат точки первого треугольника for (int i = 0; i < 3; ++i) { dv[0][i] = N1.ScalarProduct(V[0][i]) + d1; sign[0][i] = Math.Abs(dv[0][i]) > epsilant ? Math.Sign(dv[0][i]) : 0; } //Треугольник 0 не пересекается с плоскостью другого треугольника if (sign[0][0].Equals(sign[0][1]) && sign[0][1].Equals(sign[0][2]) && !sign[0][0].Equals(0)) return false; //Треугольники в одной плоскости //Как показала практика такие случаи оооочень большая редкость if (sign[0][0].Equals(sign[0][1]) && sign[0][1].Equals(sign[0][2]) && sign[0][0].Equals(0)) { //Теперь выберем на какую плоскость (xy, yz, xz) спроецируем треугольники float aNX = Math.Abs(N1.X); float aNY = Math.Abs(N1.Y); float aNZ = Math.Abs(N1.Z); float maxN = Math.Max(aNX, Math.Max(aNY, aNZ)); //Какую компоненту будем игнорить int ignoreIndex = (aNX.Equals(maxN)) ? 0 : (aNY.Equals(maxN)) ? 1 : 2; //Какие компоненты будем использовать для 2D координат int iX = ignoreIndex == 0 ? 2 : 0; int iY = ignoreIndex == 1 ? 2 : 1; //Проверка принадлежности хотябы одной точки треугольника 0 треугольнику 1 //http://ru.stackoverflow.com/questions/464787/Точка-внутри-многоугольника for (int p = 0; p < 3; ++p) { for (int i = 0; i < 3; ++i) { triange2D[i][0] = V[1][i][iX]; triange2D[i][1] = V[1][i][iY]; } point2D[0] = V[0][p][iX]; point2D[1] = V[0][p][iY]; if (PointInTriangle2D(triange2D, point2D)) return true; } //или центр масс второго треугольника 1 попадает в треугольник 0. Заодно включает //вопрос совподения (или очень близкого к совпадению) трех точек одного треугольника и трех точек другого треугольника for (int i = 0; i < 3; ++i) { triange2D[i][0] = V[0][i][iX]; triange2D[i][1] = V[0][i][iY]; } point2D[0] = (V[1][0][iX] + V[1][1][iX] + V[1][2][iX]) / 3f; point2D[1] = (V[1][0][iY] + V[1][1][iY] + V[1][2][iY]) / 3f; if (PointInTriangle2D(triange2D, point2D)) return true; return false; } Vertex N0 = (V[0][1] - V[0][0]).VectorProduct(V[0][2] - V[0][0]); float d0 = -N0.ScalarProduct(V[0][0]); for (int i = 0; i < 3; ++i) { dv[1][i] = N0.ScalarProduct(V[1][i]) + d0; sign[1][i] = Math.Abs(dv[1][i]) > epsilant ? Math.Sign(dv[1][i]) : 0; } //Треугольник 1 не пересекается с плоскостью другого треугольника if (sign[1][0].Equals(sign[1][1]) && sign[1][1].Equals(sign[1][2]) && !sign[1][0].Equals(0)) return false; //Треугольники на разных плоскостях Vertex D = N0.VectorProduct(N1); float aDX = Math.Abs(D.X); float aDY = Math.Abs(D.Y); float aDZ = Math.Abs(D.Z); float maxD = Math.Max(aDX, Math.Max(aDY, aDZ)); int Tindex = (aDX.Equals(maxD)) ? 0 : (aDY.Equals(maxD)) ? 1 : 2; for (int j = 0; j < 2; ++j) { //l и r это индексы точек находящихся по одну из сторон плоскости j int c = 1, l = 0, r = 2; if (sign[j][0].Equals(sign[j][1])) { c = 2; r = 0; l = 1; } else if (sign[j][1].Equals(sign[j][2])) { c = 0; r = 2; l = 1; } //Иначе оставляем без изменений for (int i = 0; i < 3; ++i) pv[j][i] = pv[j][i] = V[j][i][Tindex];//D.ScalarProduct(V[j][i]); //pv[j][i] = V[j][i][Tindex]; t[j][0] = pv[j][l] + (pv[j][c] - pv[j][l]) * dv[j][l] / (dv[j][l] - dv[j][c]); t[j][1] = pv[j][r] + (pv[j][c] - pv[j][r]) * dv[j][r] / (dv[j][r] - dv[j][c]); if (t[j][0] > t[j][1]) { float _t = t[j][0]; t[j][0] = t[j][1]; t[j][1] = _t; } } return (t[0][0] < t[1][1]) && (t[0][1] > t[1][0]); }
где ScalarProduct и VectorProduct это векторные и скалярные произведения соответственно
public float ScalarProduct(Vertex rhs) { return X * rhs.X + Y * rhs.Y + Z * rhs.Z; }
public Vertex VectorProduct(Vertex rhs) { return new Vertex((Y * rhs.Z) - (Z * rhs.Y), (Z * rhs.X) - (X * rhs.Z), (X * rhs.Y) - (Y * rhs.X)); }

Переворот страницы по нажатии на кнопку

Использую этот код чтобы переворачивать страницу. всего 15 страниц
-(IBAction) next:(id)sender {
NSUInteger page1 = 1; NSUInteger page2 = 4;
DataViewController *firstViewController = [self.modelController viewControllerAtIndex:page1 storyboard:self.storyboard]; DataViewController *secondViewController = [self.modelController viewControllerAtIndex:page2 storyboard:self.storyboard];
NSArray *viewControllers = nil;
viewControllers = [NSArray arrayWithObjects:firstViewController, secondViewController, nil];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
}
Проблема в том что я могу выбрать только 2 страницы ( из 15 могу переворачивать 1 и 4)
NSUInteger page1 = 1;
NSUInteger page2 = 4;
Как мне переворачивать все страницы от 1 - 15?
UPD
Ваш код работает. Но когда страницы заканчиваются приложение вылетает. Я использую этот код в RootViewController т.к. кнопку с действием могу создать только в нем, а массив с данными находится в ModelController где я не могу создать кнопку с действием. Как мне остановить перелистывание, когда страницы заканчиваются?
- (void)nextPage:(id)sender {
DataViewController *ViewController1 = self.pageViewController.viewControllers[0]; DataViewController *ViewController2 = self.pageViewController.viewControllers[1];
NSUInteger ViewControllerIndex1 = [self.modelController indexOfViewController:ViewController1] + 2; NSUInteger ViewControllerIndex2 = [self.modelController indexOfViewController:ViewController2] + 2;
DataViewController *firstViewController1 = [self.modelController viewControllerAtIndex:ViewControllerIndex1 storyboard:self.storyboard]; DataViewController *secondViewController1 = [self.modelController viewControllerAtIndex:ViewControllerIndex1 storyboard:self.storyboard];
NSArray *viewControllers = nil;
viewControllers = [NSArray arrayWithObjects:firstViewController1, secondViewController1, nil];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
}


Ответ

В методе next необходимо реализовать логику перелистывания для двух страниц. Т.е есть массив элементов, определяющих количество страниц в ModelController его можно вынести в хедер класса для видимости. И в RootViewController можно им пользоваться. А в классе RootViewController написать условие, чтобы не выходить за пределы массива, когда переписываются страницы. Для автоматического перелистывания нужно создать таймер в классе RootViewController, например в методе viewDidLoad
NSTimer *timer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(nextPage:) userInfo:nil repeats:YES]; [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

Згрузка и отображение процесса

Использую этот код чтобы загрузить картинки
-(IBAction) downloadButton:(id)sender {
if(_downloadTask == nil){
_url1 =[NSURL URLWithString:@"someUrl"]; _url2 =[NSURL URLWithString:@"someUrl"]; _downloadTask = [_session downloadTaskWithURL:_url1]; _downloadTask1 = [_session downloadTaskWithURL:_url2]; [_downloadTask resume]; [_downloadTask1 resume];
} else [_downloadTask resume]; [_downloadView removeFromSuperview]; [_downloadButton removeFromSuperview]; [_downloadButtonCancel removeFromSuperview];
} }
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
_paths1 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); _documentsDirectory1 = [_paths1 objectAtIndex:0]; _filePath1 = [_documentsDirectory1 stringByAppendingPathComponent:@"1.png"]; _fileExists1 = [[NSFileManager defaultManager] fileExistsAtPath:_filePath1 isDirectory:false];
_paths2 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); _documentsDirectory2 = [_paths2 objectAtIndex:0]; _filePath2 = [_documentsDirectory2 stringByAppendingPathComponent:@"2.png"]; _fileExists2 = [[NSFileManager defaultManager] fileExistsAtPath:_filePath2 isDirectory:false]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *urlData1 = [NSData dataWithContentsOfURL:_url1]; [urlData1 writeToFile:_filePath1 atomically:YES];
NSData *urlData2 = [NSData dataWithContentsOfURL:_url2]; [urlData2 writeToFile:_filePath2 atomically:YES]; });
И этот код для отображения хода загрузки в процентах
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite; { dispatch_async(dispatch_get_main_queue(), ^{
float progress = [[NSNumber numberWithInteger:totalBytesWritten] floatValue]; float total = [[NSNumber numberWithInteger:totalBytesExpectedToWrite] floatValue];
NSString *percentage = [NSString stringWithFormat:@"%.f%%", ((progress / total) * 100)];
NSLog(@"%.f%%", percentage);
if (!_label) {

_label = [[UILabel alloc] initWithFrame:CGRectMake(300, 130, 42, 19)];
_label.numberOfLines = 1; _label.baselineAdjustment = UIBaselineAdjustmentAlignBaselines; _label.adjustsFontSizeToFitWidth = YES; _label.minimumScaleFactor = 10.0f/12.0f; _label.clipsToBounds = YES; _label.backgroundColor = [UIColor clearColor]; _label.textColor = [UIColor whiteColor]; _label.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:_label];
}
_label.text = percentage;
Проблема в том, что label не отображает загрузку от 1% до 100%. а беспорядочно показывает разные цифры. Как это исправить?


Ответ

Так ты ведь два урла сразу грузишь, вот они оба одновременно свой прогресс и показывают. Нужно или грузить их по очереди, или по параметру downloadTask:(NSURLSessionDownloadTask *)downloadTask определять какой это таск и менять соответствующий label. Также можно вести один общий прогресс для двух урлов.

Objective-C: проверка наличия файла

Загружаю zip файл в папку в моем приложении. Наблюдаю за прогрессом загрузки от 1% до 100% в моем label. После того, как label = 100% я не нахожу файл в папке. Он появляется спустя 50 секунд. Как я могу постоянно проверять наличие файла в течение 50 секунд, чтобы точно знать кода он появится в папке?
код загрузки
-(IBAction) downloadButton:(id)sender { if (_HighScore == 2) {
_url1 =[NSURL URLWithString:@"link2.zip"];
_downloadTask1 = [_session downloadTaskWithURL:_url1];
[_downloadTask1 resume]; } - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
if (downloadTask == _downloadTask1) { _documentsDirectory1 = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; _zipPath1 = [_documentsDirectory1 stringByAppendingPathComponent:@"2.zip"]; } dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (downloadTask == _downloadTask1) { NSData *urlData1 = [NSData dataWithContentsOfURL:_url1]; [urlData1 writeToFile:_zipPath1 atomically:YES];}
}); }
UPD
_documentsDirectory1 = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; _zipPath1 = [_documentsDirectory1 stringByAppendingPathComponent:@"2.zip"]; _destinationPath1 = [_documentsDirectory1 stringByAppendingPathComponent:@"MediaData"]; _fileExists1 = [[NSFileManager defaultManager] fileExistsAtPath:_zipPath1 isDirectory:false]; if( [SSZipArchive unzipFileAtPath:_zipPath1 toDestination:_destinationPath1] != NO ) { NSLog(@"Dilip Success"); }else{ NSLog(@"Dilip Error"); }


Ответ

как уже написал в комментарии, у вас скачивание происходит два раза - первый вы скачиваете через NSSession, и когда он закончил скачивать и выполнил
- (void)URLSession: downloadTask: didFinishDownloadingToURL:
вы скачиваете еще раз используя
[NSData dataWithContentsOfURL:_url1]
Что вам надо делать, в didFinishDownloadingToURL просто смотреть куда файл скачан и его оттуда брать. типа такого:
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSURL *documentsFolder = [paths objectAtIndex:0];
NSFileManager *fileManager = [NSFileManager defaultManager]; NSURL *newLocation = [NSURL URLWithString:[NSString stringWithFormat:@"file://%@/myCoolFile.txt", documentsFolder]];
NSError *error; [fileManager copyItemAtURL:location toURL:newLocation error:&error];
}

Множественное наследование через интерфейсы, работа с общими полями и свойствами

Планирую разделить один большой класс на 5 частей следующей стратегией.
Imports ConsoleApplication1
Module Module1
Interface IA Function AFunc() As Integer End Interface
Class A Implements IA
Public Function AFunc() As Integer Implements IA.AFunc
Return 1 End Function
End Class
Interface IB Function BFunc() As Integer End Interface
Class B Implements IB
Public Function BFunc() As Integer Implements IB.BFunc
Return 2 End Function
End Class
Class AB Implements IA, IB
Protected _a As New A Protected _b As New B
Protected _somePropertyOne As String = "value1"
Private _somePropertyTwo As String = "value2" Public Property SomePropertyTwo() As String Get Return _somePropertyTwo End Get Set(ByVal value As String) _somePropertyTwo = value End Set End Property
Public Function AFunc() As Integer Implements IA.AFunc Return _a.AFunc() End Function
Public Function BFunc() As Integer Implements IB.BFunc Return _b.BFunc() End Function
End Class
Sub Main()
Dim ab As New AB
Console.WriteLine(ab.AFunc) Console.WriteLine(ab.BFunc) Console.ReadLine()
End Sub
End Module
Возможно это и неправильно, но задача, требует на данном этапе реализовать разделение таким образом, чтобы все методы из набора подклассов, имели доступ к набору общих свойств (в данном случае _somePropertyOne и SomePropertyTwo)
Как это правильнее реализовать?
Куда перенести _somePropertyOne и SomePropertyTwo?
В моем случае идеально подошли Partial Class


Ответ

Используй методы-расширения.
Imports System Imports System.Runtime.CompilerServices
Public Interface ICommon Property Value As Integer End Interface
Public Module IAExts Public Function FuncA(ByVal Obj As ICommon) As Integer Return 1 + Obj.Value End Function End Module
Public Module IBExts Public Function FuncB(ByVal Obj As ICommon) As Integer Return 2 + Obj.Value End Function End Module
Public Class Smth Implements ICommon Public Property Value As Integer Implements ICommon.Value End Class
Public Module Module1 Public Sub Main() Dim X As New Smth() With {.Value = 77} Console.WriteLine(x.FuncA()) Console.WriteLine(x.FuncB()) End Sub End Module

“Стрим” экрана (демонстрация экрана). Android API: MediaProjection

В официальном Android API написано следующее:
"Метод createVirtualDisplay позволяет вашему приложению записывать экран в объект Surface, который ваше приложение может отправить по сети."
У меня есть приложение, которое при нажатии на кнопку "Начать запись" начинает запись экрана.

При нажатии "Остановить запись" - останавливает.

При нажатии на "Play" - воспроизводит последнее видео, которое было записано.

Код я скопировал взял отсюда. Тут все вроде красиво и с объяснениями.
У меня есть сервер, написаный с помощью datagram сокетов, который принимает и возвращает пакеты.
Мой вопрос: как сделать "стрим" своего экрана (демонстрацию своего экрана)? Если делать это как-то через объект Surface, то как именно (есть ли примеры кода)?
P.S. Я читал в интернете что-то про Parcel.
Parcel – это контейнер для передачи данных.
Возможно ли его использовать для выполнения задачи?


Ответ

У меня получилось делать скриншоты и отправлять их. Сделал это через TCP. Вот. P.S. Приложение не доделано, но задача выполнена.

Андроид. Управление scrollVIew

В общем проблема такая: внутри скрол вьюва лежит imageView с определёным обработчиком касаний. И один из жестов - движение пальцем снизу вверх. Но вместо этого жест перехватывает скроллер и экран прокручивается. Как сделать так, чтобы при проведении пальцем именно по этой картинке работал обработчик вместо скрола?


Ответ

Я НАШЁЛ РЕШЕНИЕ!!! В общем поэксперементировал с разными методами. Простым языком. Нужно создать свой класс, расширяющий ScrollView, и переопределить в нём метод onInterceptTouchEvent, написав ему всего одну единую строчку "return false". И всё =)

Status Bar в iOS 7

Наверняка, если вы уже сталкивались с iOS 7, вы понимаете, о чем идет речь:
В iOS7 похоже изменилась система отсчета у view-объектов, и если запустить проект, работающий нормально в iOS <= 6.1, в iOS 7, его контент будет выводиться поверх прямо статус бара (на всякий случай "статус бар" - это где часы, вай-фай, моб. оператор...), а внизу будет пустая полоса 20px. То есть как будто бы views стали отсчитываться с (0, 0) экрана, а не как раньше с (0, 20).
На SO на этот счет внятных ответов я не нашел, так как там все вопросы про iOS 7 минусуют и закрывают, и говорят, что нужно идти на Apple forums. Единственное, что я нашел это вот этот неубедительный ответ, который опять же ссылаясь на Apple forums, утверждает, что прежнее поведение отсчета views с 20 пикселей является "an old bug" и что нынешнее поведение "is actually a fix". На самих форумах Apple тоже внятной информации с точным решением я пока не нашел.
Я прочитал iOS7 UI Transition guide, и видел, что
In iOS 7, view controllers use full-screen layout.
но мне интересно (внимание, вопрос!), можно ли с помощью кода сохранить старое поведение предыдущих версий iOS и в версии iOS 7.0? Изменение разных параметров, которые Apple описывает в этом гайде, не дало мне нужного, даже приблизительно, результата.
Примечание: я имею в виду поведение проектов, написанных руками, без использования Storyboards.


Ответ

Я в своё время нашёл решение для своего вопроса, и так и не собрался оформить его здесь в виде ответа. Не очень удобное, но работающее самым надёжным из всех возможных образом. Кратко: я завернул view-иерархию каждого контроллера в ещё один UIView *compatibilityContainerView, который и выполнял необходимое мне позиционирование. В одной из ссылок на эту тему: Wrestling with Status Bars and Navigation Bars on iOS 7 этот способ описан под цифрой 9. Теперь же похоже это постепенно становится неактуальным, так как Apple говорит нам в принудительном порядке адаптировать приложения под iOS 7: С 1 февраля 2014 все новые приложения должны быть адаптированы под iOS7

Как найти наибольшую биклику, допуская неполное совпадение?

Дан двумерный массив булевых значений. Строки это аккаунты, столбцы – различные свойства каждого аккаунта: «состоит в группе А», «совершал покупки» и т.п.
Надо найти максимальную биклику (полный двудольный граф) – т.е. тот наибольший набор аккаунтов×свойств, где свойства true
Задача NP-полная, и с её реализацией я кое-как в лоб разобрался. Но теперь два усложнения.
хочется сравнивать «нечётко»: допустить вхождение в биклику аккаунтов, у которых недостаёт 1-2 (задаётся параметром нечеткости) свойств. Лучше посчитаем, как будто они у них true, если это позволит включить их в наибольший набор. Неужели для каждой найденной клики нужно зановой перебрать все данные, проверяя гипотезы о каждом свойства, которое можно бы добавить? Подскажите алгоритм. размер исследуемых наборов растёт. Может, вы прошли курс Machine Learning или прочие BigData – посоветуйте методики поиска, альтернативные полному перебору? Я краем уха слышал, есть такие, эффективно работающие на больших объёмах, пусть, дающие приблизительный результат – объясните, пожалуйста, «на пальцах», как их можно применить к задаче?
Иллюстрации проблемы

Синие ячейки true, белые false. Нечёткая максимальная биклика обведена красным – в каждой строке добавили по три «фантомных» ячейки (серые). Порядок строк/столбцов не имеет значения. Максимальная биклика вовсе не обязательно будет сплошным прямоугольником, это только для иллюстрации.

Например, здесь светло-синие ячейки были отброшены на этапе оптимизации, а оставшиеся формируют две би-клики: строки (3,5) × столбцы (1,3,4,6) и (3,4,5)×(1,3). Однако, если включить fuzziness на 2, то можно добавив в 4-й строке столбцы (4,6), а в строках (3,5) столбец 5 – получить ещё большую биклику (3,4,5)×(1,3,4,5,6).


Ответ

В случае нечеткого определения понятия "полнота" возможны серьезные отклонения в определении "максимальной" биклики в зависимости от метрики, по которой оценивается максимум, так как наличие ненулевого числа false в строках и столбцах биклики позволяет выбирать метрику так, что "максимальными" для каждой метрики будут разные биклики.
Например, в случае метрики "превышение true над false на всей биклике" (количество заполненных против количества незаполненных клеток) и нечеткости 3 на примере с прямоугольником максимумом окажется биклика из столбцов 1,2,6,7 прямоугольника и всех его строк, с метрикой +8. При использовании метрики "всего истин" (число заполненных прямоугольников) выделенный прямоугольник является максимальным. Таким образом, для задачи с нечеткостью метрику нужно жестко задать, причем в зависимости от метрики может варьироваться сам алгоритм выбора биклики.
В общм случае (если метрика линейно зависит от количества строк и столбцов, участвующих в биклике) подойдет жадный алгоритм захвата столбцов. Вначале сортируем столбцы по количеству строк с данным атрибутом, установленным в true, потом включаем в множество столбцов по очереди и смотрим изменение метрики. Для параметра нечеткости начальное рассмотрение должно включать минимум (параметр нечеткости)+1 столбцов, иначе биклика с нечеткостью захватит весь массив строк - этого нам явно не надо. После появления набора столбцов добавляем по одному так, чтобы промежуточное значение метрики возрастало. Количество строк в биклике будет убывать, так как не всегда у имеющихся строк будет true в новом столбце, и какие-то из них выпадут по причине превышения false предела нечеткости, в итоге либо добавим все, либо на каком-то этапе ни одной не получится добавить. Проверяем, удастся ли выкинуть хоть один столбец чтобы метрика полезла вверх, если да, выкидываем и продолжаем, пока изменение включения одного столбца не приведет к увеличению метрики. Выдаем её как локальный максимум. Для очистки совести можно рассмотреть наибольшую по метрике стартовую комбинацию из столбцов, не вошедших в найденную биклику и точно так же её обработать. Если сойдется к этому же набору, его выдаем, иначе проверяем, какая из найденных биклик больше, и если новая, проверяем ещё какую-нибудь комбинацию на случай нескольких локальных максимумов, пока либо не придем к уже найденному локальному максимуму, либо к меньшему, тогда возвращаем текущий локальный максимум как ответ.

Плавность анимации при разных @keyframes

Всем привет! Подскажите пожалуйста, как сделать "плавность" анимации.
У меня есть @keyframes, который описывает поведение анимации при загрузки. А при ховере, подключается другой @keyframes (анимация и ее ход меняется).
Между их сменой происходит резкость.
Вот пример резкости http://jsfiddle.net/g4wvqrL8/
Вопрос: как при разных @keyframes при ховере сделать плавную смену 2х типов анимация?
Пробовала делать transition (смещала их на нужную траекторию при ховере и начинать новую анимацию, но плавность все равно не было).
Или же как начинать анимацию с места, где остановилась анимация до этого??
Подскажите , всем заранее спасибо!
.icon-1 { width: 3em; height: 3em; margin: 85px auto; animation: pull 3s infinite reverse ease-in-out } .icons { width:80%; margin: 0 auto; height:90px; } .icons:hover { animation: rotate360 4s infinite reverse cubic-bezier(0.4, 0, 1, 1); } @keyframes pull { 0% { transform: translateY(0px); } 50% { transform: translateY(-55px); } 100%{ transform: translateY(0px); } } @keyframes rotate360 { 0% { transform: rotate(0deg) translateX(30px); } 100% { transform: rotate(360deg) translateX(30px); } }



Ответ

Один из вариантов, отловить конец итерации анимации и потом ее отключить. Возможно вам нужно подправить размеры контейнеров, так как при вращении мышь сходит с контейнера.
http://jsfiddle.net/g4wvqrL8/3/
$(function() { function whichTransitionEvent() { var t, el = document.createElement("fakeelement"); var transitions = { "transition": "animationiteration", "OTransition": "oanimationiterationd", "WebkitTransition": "webkitAnimationIteration" } for (t in transitions) { if (el.style[t] !== undefined) { return transitions[t]; } } } var transitionEvent = whichTransitionEvent(); var $icons = $(".icons"), $icon1 = $(".icon-1"); $icons.hover( function() { var self = $(this); $icon1.addClass("pause"); $icons.addClass("animate-rotate"); }, function() { $icons.one(transitionEvent, function(event) { $icons.removeClass("animate-rotate"); $icon1.removeClass("pause"); }); } ); }); .icon-1 { width: 3em; height: 3em; margin: 85px auto; animation: pull 3s infinite reverse ease-in-out } .icons { width: 80%; margin: 0 auto; height: 90px; } .pause { animation-play-state: paused; -webkit-animation-play-state: paused; } .animate-rotate { animation: rotate360 4s infinite reverse forwards cubic-bezier(0.1, 0, 1, 1); } @keyframes pull { 0% { transform: translateY(0px); } 50% { transform: translateY(-55px); } 100% { transform: translateY(0px); } } @keyframes rotate360 { 100% { transform: rotate(1turn); } }