Страницы

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

четверг, 28 ноября 2019 г.

Непонятный результат вычисления

#c_sharp


Почему в данном случае a будет равно 20, а не 21?

int a = 10;
a += a++;
Console.WriteLine(a);

    


Ответы

Ответ 1



Это вариация классической задачи про ++i + ++i в несколько упрощенном варианте. В C++ - это undefined behavior, и результатом в большинстве компиляторов будет 21. Цитируя lurkmore: согласно стандартам С и С++, побочные эффекты (то есть инкремент в данном случае) могут быть применены в любой удобный для компилятора момент между двумя точками следования. Конструкцию i = ++i + ++i; компилятор вправе понять и как tmp=i; tmp++; i = tmp; tmp++; i += tmp; и как tmp=i; tmp++; tmp++; i = tmp + tmp; Из-за непредсказуемости поведения этот пример раньше часто предлагали объяснить на собеседованиях :) В C# результатом будет 20, т.к. порядок вычисления явно задан спецификацией. В C# нет никаких точек следования, компилятор не настолько свободен при оптимизации выражений, так что он вычисляет в том порядке, в котором ему приказали: += - это compound assignment operator. Он не самостоятельный оператор (не допускает отдельной перегрузки, и т.д.), а просто шорткат для a = a + a++; Т.е. он просто берет результат вычисления a (10), прибавляет к нему результат вычисления a++ (10) и складывает сумму (20) обратно в a. При этом операнды вычисляются именно слева направо. Процесс вычисления постфиксного оператора a++ описан в спецификации C#, 7.6.9 Postfix increment and decrement operators, и он следующий: Сохраняется текущее значение a. (10) Вызывается оператор (++) с передачей сохраненного значения a в качестве аргумента. Результат вычисления оператора (11) сохраняется в a. (которое позже перезатрется результатом сложения) Сохраненное значение a возвращается как результат операции. (10) Поэтому a + (a++) -> 20 (a++) + a -> 21

Ответ 2



Значение присвоения оператора инкремента не используется ни в одном из путей выполнения, что-то похожее скажет ReSharper на такой код a += a++; сообщение: Value assigned is not used in any execution path Вы попросту потеряете свой постфиксный инкремент, так как он выполняется после того, как выполнится операция сложения и перед присваиванием. Вот если Вы используете префиксный инкремент, тогда получите в результате 21. int a = 10; a += ++a; Console.WriteLine(a); Так как операция префиксного инкремента выполнится раньше, чем выполнится сложение и присваивание. В префиксной форме инкремент или декремент выполняется до использования значения при вычислении выражения. В постфиксной форме инкремент или декремент выполняется после использования значения при вычислении выражения. Ссылки: Оператор ++ (справочник по C#) Оператор -- (Справочник по C#)

Ответ 3



a += a++; ^---------- 10 ^----- 10 ^^--- 11 ^^^--- значение 10, но a=11 ^^------- 10+10 = 20

Зачем добавлять в конструктор дочернего класса super(), если компилятор делает это автоматически?

#java #наследование #конструктор


Зачем добавлять в конструктор дочернего класса вызов super(), если компилятор делает
это автоматически? 

Я имею в виду, что в любом случае вначале будет выполнятся конструктор родительского
класса и только потом дочернего, зачем же тогда прописывать это вручную?
    


Ответы

Ответ 1



Потому, что в super() вы можете передавать аргументы, в том случае, если вам нужно, чтобы выполнился конструктор с аргументами родительского класса. И от того, аргументы какого типа вы туда передадите, зависит то, какой конструктор выполнится (если их несколько).

Ответ 2



Не обязательно в каждом конструкторе вызывать super(). Если базовый класс не содержит конструктора с аргументами, тогда в классах наследниках не обязательно писать super(), это подразумевается (эти вызовы расставит компилятор). Если же у базового класса есть конструктор с аргументами, тогда уже Вам необходимо указать эти аргументы, соответственно необходимо и конструктор базового класса вызвать. Можно так же передать управление какому-то конструктору из текущего класса, вызвав this(), но эта цепочка должна привести к вызову конструктора базового класса, рассмотрите этот пример class Base { int i; Base(int i) { this.i = i; } } public class Super extends Base { boolean b; String s; Super(String s, boolean b) { this(s); this.b = b; } Super(String s) { super(1); this.s = s; } } Таким образом директивы this и super позволяют переиспользовать конструкторы и не плодить одинаковый код инициализации

Почему g++ и msvc по-разному интерпретируют код?

#c++ #visual_c++ #g++


Дан код:

int main() {
    int a = 8;
    int b = 100;
    float d;
    int c = ++a * a++;
    d = b / (--a);
    return 0;
}


но почему-то в g++ переменная с равна 90, а в msvc она равна 81.
    


Ответы

Ответ 1



Неопределенное поведение классическое: int c = ++a * a++; Для C++98: Двухкратная запись в переменную a в пределах одной точки следования. Для C++11: Нарушение правил порядка вычисления. Программа ошибочна. Компилятор может реагировать случайным образом.

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

#css #вёрстка




Подскажите как такое сверстать. Интересует именно блоки в виде трапеций с обводкой.
Фон, стрелки, текст - то все понятно.
    


Ответы

Ответ 1



Я предлагаю вашему вниманию альтернативное решение. Из минусов: поскольку смещение и ширина срезов вычисляется не по математической формуле, а "на глазок", есть небольшой косячок на границе в левом верхнем углу блока. лишняя разметка в примере нет префиксов Из плюсов: на текст нет никакого влияния. Основная идея: С помощью псевдоэлементов и дополнительной разметки мы можем "срезать" лишнее с краев прямоугольника, чтобы превратить его в трапецию. Чтобы получился не просто срез, а граница блока, будем использовать два одинаковых по размеру блока разного цвета, разместив их один над другим с небольшим смещением. Реализация: * { box-sizing: border-box; } /* Обертка нужна для обрезки "лишнего" в разметке */ .wrapper { margin: 0 20px; max-width: 510px; overflow: hidden; } /* трапеция*/ .item { border: 2px solid #606060; height: 120px; background: #f5f5f5; position: relative; display: flex; justify-content: center; align-items: center; /* Чтобы текст не залезал на наши будущие срезы */ padding: 10px 30px; } /* Перекрашиваем четные трапеции */ .item:nth-child(even) { background: #606060; color: #fff; } /* Подложки, для имитации границы */ .item::before, .item::after, .item .border { content: ''; display: block; height: 100%; width: 80px; position: absolute; } /* Нижний слой подложки для цвета границы */ .item::before, .item::after { background: #606060; top: 0; } /* Верхний слой подложки для "среза" прямоугольника */ .item .border { background: #fff; height: calc(100% + 4px); top: -2px; } /* Наклон среза для четных трапеций */ .item:nth-child(odd)::before, .item:nth-child(odd)::after, .item:nth-child(odd) .border.left { transform: skew(10deg); } .item:nth-child(odd)::after, .item:nth-child(odd) .border.right { transform: skew(-10deg); } /* Наклон среза для нечетных трапеций */ .item:nth-child(even)::before, .item:nth-child(even)::after, .item:nth-child(even) .border.left { transform: skew(-10deg); } .item:nth-child(even)::after, .item:nth-child(even) .border.right { transform: skew(10deg); } /** * Выравниваем нижний и верхний слой подложки друг относительно друга * Учитываем левый и правый срез */ .item::before { left: -70px; } .item .border.left { left: -72px; } .item::after { right: -70px; } .item .border.right { right: -72px; } /** * ::after всегда последний, поэтому надо выставить z-index для правого верхнего слоя */ .item .border.right { z-index: 1; } /** * Максимум 5 строчек текста * Вместо отображения скролла текст можно прятать */ .item > .text { line-height: 20px; max-height: 100%; overflow-y: auto; }
Пример контента
Curabitur aliquet quam id dui posuere blandit. Vestibulum ac diam sit amet quam vehicula elementum sed sit amet dui. Proin eget tortor risus. Donec rutrum congue leo eget malesuada. Praesent sapien massa, convallis a pellentesque nec, egestas non nisi. Praesent sapien massa, convallis a pellentesque nec, egestas non nisi. Nulla porttitor accumsan tincidunt. Nulla quis lorem ut libero malesuada feugiat. Nulla quis lorem ut libero malesuada feugiat. Mauris blandit aliquet elit, eget tincidunt nibh pulvinar a.
Здесь что-то написано


Ответ 2



.trapezoid-in { border: 2px solid #000; width: 400px; height: 100px; background: #ccc; transform: perspective(15px) rotateX(-1deg); margin: 6px 50px 0; } .trapezoid-out { border: 2px solid #555; width: 400px; height: 100px; background: #555; transform: perspective(15px) rotateX(1deg); margin: -6px 50px 0; }


Ответ 3



Еще как вариант * { padding: 0; margin: 0; box-sizing: border-box; } .b { max-width: 500px; margin: 25px auto; padding: 0 20px; } .b-trapezoid { background: #F5F5F5; padding: 15px; border: 2px solid #606060; height: 100px; position: relative; } .b-trapezoid:before, .b-trapezoid:after { content: ''; position: absolute; width: 15px; height: 100%; background: #F5F5F5; border: 2px solid #606060; } .b-trapezoid:before, .b-trapezoid:nth-of-type(even):before { top: -2px; left: -7px; -webkit-transform: skew(7deg); transform: skew(7deg); border-right: none; } .b-trapezoid:after, .b-trapezoid:nth-of-type(even):after { top: -2px; right: -7px; background: #F5F5F5; -webkit-transform: skew(-7deg); transform: skew(-7deg); border-left: none; } .b-trapezoid:nth-of-type(even), .b-trapezoid:nth-of-type(even):before, .b-trapezoid:nth-of-type(even):after { background: #606060; color: #fff; } .b-trapezoid:nth-of-type(even):before { -webkit-transform: skew(-7deg); transform: skew(-7deg); border-left: none; } .b-trapezoid:nth-of-type(even):after { -webkit-transform: skew(7deg); transform: skew(7deg); border-right: none; } .b-trapezoid-content { display: table; width: 100%; height: 70px; text-align: center; } .b-trapezoid-content-item { display: table-cell; vertical-align: middle; } .b-trapezoid-content-text { max-height: 75px; overflow-y: auto; } .b-trapezoid-content-text::-webkit-scrollbar { width: 4px; } .b-trapezoid-content-text::-webkit-scrollbar-button { background: #ccc; height: 0; } .b-trapezoid-content-text::-webkit-scrollbar-track-piece { background: #ccc; } .b-trapezoid-content-text::-webkit-scrollbar-thumb { background: #4682B4; }

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?

Как добиться эффекта сложенного гармошкой листа с помощью CSS?



Различия методов Find(), FirstOrDefault() при использовании с Entity Framework

#c_sharp #.net #entity_framework #linq #c_sharp_faq


Если нужно получить запись из базы данных по ее первичному ключу, можно воспользоваться
и тем и другим методом. Оба метода вернут объект сущности, если запись присутствует
в базе, в противном случае вернут null.

В чем их разница и когда какой метод использовать?
    


Ответы

Ответ 1



Для поиска и получения объекта сущности можно воспользоваться методами: Find(), First(), FirstOrDefault(), Single(), SingleOrDefault(). Рассмотрим каждый: Метод Find() принимает в качестве параметра первичный ключ записи. Его особенность состоит в том, что в отличие от остальных методов, он сначала обращается к памяти и ищет запись среди объектов контекста, отслеживаемых EntityFramework'ом, и только потом (если ничего не нашел) выполняет запрос к бд. Если в контексте найдется объект, который еще не сохранен в базе, метод Find() все равно вернет его (с состоянием Added). Если запись не будет найдена ни там ни там, вернет null. Генерируемый SQL запрос: SELECT TOP (2) [Extent1].[Id] AS [Id], [Extent1].[Title] AS [Title], FROM [dbo].[Topics] AS [Extent1] WHERE [Extent1].[Id] = @p0 Стоит обратить внимание, что в выборку попадает не одна запись, а две SELECT TOP (2). Это используется внутренними механизмами EF для проверки уникальности записи. Если в результате окажется более одной записи с одним и тем же первичным ключем, EF сгенерирует исключение: System.InvalidOperationException: "Последовательность содержит более одного элемента" Метод FirstOrDefault() принимает в качестве параметра предикат, что дает возможность искать не только по первичному ключу, но и по любому составленному условию. Например, найдем запись, у которой Title == "test": var topic = context.Topics.FirstOrDefault(topic => topic.Title == "test"); FirstOrDefault() в отличии от Find() каждый раз выполняет запрос к базе, не зависимо от того есть ли данные в контексте. Если из базы придет запись, отличающаяся от той что лежит в контексте, EF вернет запись из контекста. Если записи не окажется в базе, вернет null, даже если она есть в контексте. Генерируемый SQL запрос: SELECT TOP (1) [Extent1].[Id] AS [Id], [Extent1].[Title] AS [Title], FROM [dbo].[Topics] AS [Extent1] WHERE [Extent1].[Id] = @p__linq__0 Тут ищет только одну запись SELECT TOP (1). Если окажется что записей несколько, вернет первую. Метод First() аналогичен FirstOrDefault() с одним отличием - если запись не найдена, будет сгенерировано исключение: System.InvalidOperationException: "Последовательность не содержит элементов" Метод SingleOrDefault() аналогичен FirstOrDefault() и возвращает объект сущности, либо null. Однако запрос генерирует подобный методу Find(): SELECT TOP (2) [Extent1].[Id] AS [Id], [Extent1].[Title] AS [Title], FROM [dbo].[Topics] AS [Extent1] WHERE [Extent1].[Id] = @p__linq__0 И при обнаружении более одной записи выкидывает исключение: System.InvalidOperationException: "Последовательность содержит более одного элемента" Метод Single() аналогичен SingleOrDefault() и отличается тем, что если запись не найдена, будет сгенерировано исключение: System.InvalidOperationException: "Последовательность не содержит элементов" Подведем итоги: Когда использовать Find()? Когда искать нужно по первичному ключу и выбрать нужно все данные сущности. Find() не выполняет запрос, если запись уже загружена в контекст и, как следствие, будет превосходить в производительности все остальные методы. Однако если нужно выбрать какие-то определенные поля (например только Id и Title), придется воспользоваться остальными методами. То же касается и подгрузки зависимых данных (например через Include()) - Find() это сделать не даст. Когда использовать остальные методы? Если нужна выборка определенных полей сущности или нужно также загрузить зависимые данные. Какие именно методы использовать зависит от индивидуальных требований: если вам нужно проверить существование записи (без генерации исключений), подойдут методы *OrDefault(): var topic = context.Topics .Select(topic => new { topic.Id, topic.Title }) .FirstOrDefault(topic => topic.Id == 44); if (topic == null) { // ... } Если предполагается, что контекст может содержать локальные копии данных, можно получить их оттуда, не выполняя запроса к базе. Для этого нужно обратиться к свойству Local объекта DbSet: Var topic = context.Topics.Local.FirstOrDefault(topic => topic.Id == topicId) ?? context.Topics.FirstOrDefault(topic => topic.Id == topicId); Используемые источники: MSDN: Entity Framework Querying and Finding Entities Primer on Selecting Data Using Entity Framework StackOverflow: Are Find and Where().FirstOrDefault() equivalent? StackOverflow: Using .Find() & .Include() on the same query

Как работает GROUP BY в MySQL?

#mysql #sql


Привет.

Вопрос по sql по клаузуле GROUP BY. 


Рассмотрим группировку по ОДНОМУ столбцу. Пример:

SELECT DEPARTMENT_ID, SUM(SALARY) 
FROM Employees
GROUP BY DEPARTMENT_ID;




То есть, в столбце DEPARTMENT_ID ищется уникальное (похоже на DISTINCT) значение
отдела, например, 30, затем ищутся все строки, где упоминается отдел 30 в данной таблице,
из этих строк берутся значения из столбца SALARY и суммируются (SUM). Потом ищется
другой покупатель и все повторяется. В итоге я получаю сколько получил вообще денег
каждый отдел.

Не понимаю момент: у меня есть 6 строк, в которых есть столбец DEPARTMENT_ID со значением
30. Какая из строк пойдет в таблицу-SELECT и почему? То есть, в таблице Employees было
шесть строк с DEPARTMENT_ID 30, а в таблице-SELECT такая строка только одна. Как вообще
эта группировка работает?
Рассмотрим группировку по двум столбцам. Ее я вообще не понимаю. Даже картинки нормальной
не нашел, из которой было бы понятно. Просмотрел кучу статей и книг по этому вопросу,
но не понял ничего.

    


Ответы

Ответ 1



Добавлю с примером запросов и вывода GROUP BY по двух полях. Смотреть можна по таблице в которую например сохраняеться какой пользователь(user_id) вносил деньги, на какой счет(account) и сколько(balance). Например нужно узнать сколько каждый пользователь внес на каждый со своих счетов. SELECT MIN(user_id), MIN(account), SUM(balance) FROM `t1` GROUP BY user_id, account; Работает GROUP BY по двух полях так же как и по одному, сначала сортирует, а потом смотрит если оба значения в строке такие же как и в предыдущей строке тогда групирует эти строки. Если хотя бы одно значение не такое как в предыдущей строке тогда групировки не будет. Для 3 и больше полей GROUP BY работает так же. Результат:

Ответ 2



В выборку после group by не попадет ни одна из изначальных строк. На выходе агрегат - сумма данных в нужном разрезе. К колонкам, к которым вы явно не применили никаких групповых функций (таких как sum()), будет применена функция "первое попавшееся". Причем только в MySQL и только при выключенной опции ONLY_FULL_GROUP_BY. В остальных СУБД запрос, в котором хотя бы к одной колонке, не являющейся разрезом указанным в group by, "забыли" применить групповую функцию выдадут ошибку. Как работает group by можно прикинуть в экселе. Запишите данные на лист, отсортируйте по тем полям, которые должны быть в group by. Читая отсортированные данные подряд в любом случае когда значение в очередной строке в колонках, указанных в group by отличается от значений в предыдущей - вставьте новую строку, скопируйте значения колонок group by, а в остальные поместите формулы вроде СУММ() ячеек группы под которой подводится итог. Результат group by - это именно эти вставленные итоговые записи. СУБД работает примерно по такому же алгоритму - сначала сортирует, потом суммирует идущие подряд одинаковые записи. Добавлю про MySQL - он все таки слишком вольно к этому относится, старайтесь всегда явно применять групповые функции ко всем колонкам, что бы самому понимать что именно в них окажется, ибо 'первое попавшееся' ни чем не стандартизировано и может меняться от версии к версии и в зависимости от физического расположения записей на диске и плана выполнения запроса.

О логировании в java

#java #логирование


Приводится на хабре в статье библиотека Apache Commons Logging (не знаю смысл этой
библиотеки,  не юзал) и комментарий:


  За System.out.println для вывода логов начинающим программистам уже через неделю
обучения следует отрубать руки.


Так вот вопрос: а почему print настолько плох?

P.S. Сам я основы языка очень плохо знаю.
    


Ответы

Ответ 1



Логирование - это все-таки больше, чем вывод строк в консоль. Здесь имеют место следующие параметры: Цель: это может быть консоль (stdout), немного другая консоль (stderr), файл, удаленный сервер сбора логов Уровень логирования: для разных выводов может быть разный уровень вывода: например, в один файл мы скидываем всё, но храним только последние десять мегабайт, а в другой отправляем только сообщения уровня WARN и выше, но храним историю за последние шесть месяцев Per-package настройки: в случае, если "шалит" конкретный участок кода, можно включить логирование только для него Ротация логов: логи чаще всего надо хранить в файлах, которые нужно периодически подчищать, и при этом во время проведения работ продолжать писать логи Контекст выполнения: зачастую просто сообщения недостаточно (если транзакция провалилась, то какие входные параметры этому поспособтсвовали?), поэтому существуют штуки типа MDC, чтобы при обработке конкретного юзера перед каждым вашим сообщением добавлялась мапа {processed user id: 12345} Подстановка параметров: писать Logger.debug("Transaction #{} has failed with message '{}'", transaction.getId(), e.getMessage()) гораздо удобнее, чем писать System.out.ptintln("Transaction #" + transaction.getId() + " has failed with message '" + e.getMessage() + "'"). Кроме удобства, это позволяет не конкатенировать строки, если уровень логирования выше самого сообщения (т.е. при уровне INFO сообщения с уровнем DEBUG не будут тратить ресурсы на конкатенацию) и группировать лог-сообщения по шаблону (искать в логах вместо просто слова "transaction" конкретный шаблон). Всем этим занимается библиотека логирования, и она сильно упрощает жизнь, когда нужно перейти от одной модели к другой, например, когда логи возле приложения хранить стало нецелесообразно, для переключения на удаленный сервер достаточно подключить новый аппендер и перезапустить приложение. Кроме того, существует ситуация, когда логов настолько много, что I/O не успевает справляться - о проблемах такого рода, как правило, не думают вплоть до их появления, а в библиотеках (я надеюсь) некоторые предусмотрительные шаги уже сделаны (например, logback совершенно точно по умолчанию пытается добавить сообщение пять раз на тот случай, если что-то пошло не так).

Ответ 2



По сути, выше уже всё было сказано, добавлю ещё один практический аспект. Консоль имеет определённую емкость. И, например, если она равна 300 строк, то в случае, если в неё запишутся 500 строк, начальные 200 строк вы уже не увидите. Можно, конечно, увеличить размер буфера консоли, но тогда придётся его увеличивать постоянно, а это не лучший вариант. Особенно для большого проекта, где логи записываются практически непрерывно, и логируется большой объём данных.

Простой способ объединения массивов строк

#java #массивы #строки


Добрый день!

Мне нужно объединить два массива строкового типа, каким простым способом я могу сделать это?

String[] bothArray(String[] first, String[] second) {
    return ??;
}

    


Ответы

Ответ 1



Если разрешено использовать Java8, то можно воспользоваться классом Stream и лямбдами: import java.util.Arrays; import java.util.stream.Stream; // . . . String[] bothArray(final String[] first, final String[] second) { return Stream.concat(Stream.of(first), Stream.of(second)).toArray(String[]::new); } Компактно, красиво и не требует внешних компонентов.

Ответ 2



С помощью библиотеки Apache Commons: String[] both = (String[])ArrayUtils.addAll(first, second); отсюда Другой вариант public static String[] combine(String[] a, String[] b){ int length = a.length + b.length; String[] result = new String[length]; System.arraycopy(a, 0, result, 0, a.length); System.arraycopy(b, 0, result, a.length, b.length); return result; } источник с примерами Еще один вариант для всех типов. Тут можно не только примитивные типы использовать, а так же объектов public T[] concatenate (T[] a, T[] b) { int aLen = a.length; int bLen = b.length; @SuppressWarnings("unchecked") T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen+bLen); System.arraycopy(a, 0, c, 0, aLen); System.arraycopy(b, 0, c, aLen, bLen); return c; } источник

Ответ 3



И еще один вариант. (Редко вижу его упоминание) String[] array; StringBuilder newStr = new StringBuilder(); for(String data: array){ newStr.append(data); } return newStr.toString();

Private наследование

#c++ #ооп


Для чего нужно наследование с описателем доступа private, если все поля базового
класса станут недоступными?
    


Ответы

Ответ 1



Именно для того, чтобы все члены базового класса не были доступны снаружи (были доступны только изнутри класса, или друзьям класса). Наследование мало чем отличается от аггрегации, и class A : private B { ... }; аналогично class A { private: B b; };. Одна в отличие от private: B b;, при наследовании функции B можно вызывать как члены своего класса, т.е. не b.f(), а просто f(). Также можно унаследоваться от абстрактного класса, и переопределить его методы, не показывая все эти делати наружу, например: struct Callback { virtual void done() = 0; }; void run(Callback* b); class Cls : private Callback { public: void some() { run(this); } private: void done() override { ... } };

Ответ 2



Приватное наследование — это по существу композиция, выраженная немного по-другому. При композиции у вас вложенный объект доступен по своему имени, но не виден снаружи. При приватном наследовании вложенный объект «влит» в *this. Вообще, роль наследования — выражать отношение Is-A между классами. То есть, выражать наследование интерфейса, при этом наследование имплементации есть техническая деталь. А приватное наследование именно это и не может, при приватном наследовании наследуется именно имплементация, но не интерфейс. Поэтому практически всегда вместо приватного наследования стоит предпочесть именно композицию: она выражает ту же идею, но явно.

Ответ 3



При приватном наследовании public и protected члены базового класса будут вполне доступны, как приватные члены в производном классе.

Final переменная для анонимного класса

#java


Есть пример кода:

public static void main(String[] args){
    int a=5;
    new Thread(new Runnable(){
        @Override
        public void run() {
            System.out.println(a);
        }
    }).start();
}


Нужно использовать переменную a в анонимном классе, компилятор говорит объявить её
как final.

Почему она должна быть final?
    


Ответы

Ответ 1



Это ограничение, которое ввели разработчики спецификации: при создании анонимного класса происходит захват объектов по значению, а не по ссылке. В анонимном классе создаются закрытые поля, в которые копируются значения переданных переменных. То есть по сути реализована эмуляция замыканий. Добавление модификатора final как бы говорит программисту о том, что при использовании такого рода замыканий не будут наблюдаться побочные эффекты (представьте, что вы передали в созданный объект анонимного класса переменную, а затем изменили её "снаружи" - вы в праве ожидать, что это изменение отразится и внутри замыкания, но это не так в силу пресловутой эмуляции; однако изменение внутреннего состояния mutable объектов будет видно и там и там). Для реализации полноценных замыканий необходимо расширять жизненный цикл захватываемых объектов (это касается объектов, расположенных в стеке, которые при выходе из области видимости, в которой они объявлены, уничтожаются). Почему это не реализовано до сих пор? Для такого рода реализации необходимо внести серьезное изменение в саму архитектуру JVM. Такого рода изменения достаточно сложно внедрить по определенным причинам: потребуется много усилий для внесения изменений не только со стороны Oracle, но и со стороны сторонних разработчиков (дебаггеры, обфускаторы, IDE, компиляторы и т.д.). Внесение такого изменения может привести к утрате обратной совместимости, что отразится на множестве уже существующих приложений. Изменение может отразиться на других языках/платформах, завязанных на среде JVM. В Java 8 ввели понятие effectively final - это переменные, которые не имеют модификатора final, но могут использоваться в анонимных классах и лямбда-выражениях. Переменная будет effectively final, если после её определения она не изменяется. Соответственно на Java 8 ваш код будет скомпилирован. Дополнительные ссылки для более подробного ознакомления: Accessing Members of an Enclosing Class, Why are only final variables accessible in anonymous class? Does Java 8 Support Closures?

Ответ 2



Ваш код создаёт поток, поток запускается на выполнение, а вызвавшая поток функция (в данном случае main) может завершиться. При завершении функции все её локальные переменные, в том числе и i исчезнут, выделенная под них память возвратится системе. Следовательно, поток не должен иметь доступ к локальным переменным. Но! Если у переменной Вы укажете квалификатор final, то Вы, фактически, говорите компилятору, что это не переменная, а константа. Компилятор будет уверен, что после инициализации эта константа не изменится, поэтому со спокойной совестью вместо прямого обращения к переменной поставит внутри кода потока её копию.

Консоль Sublime Text 3

#node.js #cmd #sublime_text


Подскажите, пожалуйста, как настроить консоль в sublimetext3, чтобы не открывать
стандартную консоль (cmd) в Windows?
    


Ответы

Ответ 1



В обзоре могут содержаться субъективные суждения, основанные на опыте работы с плагинами для Sublime Text. Протестировано на Windows 32-bit 10.0.14393, Отключён контроль учётных записей, Sublime Text Build 3126. Вообще в Sublime Text по моему вероятностному суждению примерно треть плагинов совсем не работают после установки. Но расписанные в обзоре лично у меня функционируют, что доказывается скринкастами. По причине того, что использую Windows, не рассмотрены такие решения, как Tint и fish-shell. Если не упомянул что-то ещё, можете добавить. Терминология В данном обзоре встроенная консоль Windows называется «консолью» или «внешней консолью» в зависимости от контекста. Согласно автору программы ConEmu называть её cmd.exe не совсем корректно: В Windows есть встроенный терминал (или “консольное окно”) которое часто ошибочно называют “cmd.exe”. Нажмите Win+R и запустите, например, “powershell.exe”. Среди запущенных процессов не будет “cmd.exe”. В разных версиях Windows консольное окно создают разные процессы, в актуальных – это “conhost.exe”. Не ‘cmd.exe’, а просто ‘консоль’! 0. Не работающее решение 1. SublimePTY Страница плагина. Разработка давно прекращена. 1. Для запуска отдельных команд Для Sublime Text пишут плагины, облегчающие запуск только отдельных команд только для определённых инструментов программирования. Например, команды Git проще запускать с помощью плагинов Git, SideBar Git и Easygit (Не загружайте Easygit через Package Control, он не будет работать! Установите плагин вручную по ссылке). Так как в вопросе указана метка Node.js, приведу в пример плагин npm. 1. npm Плагин, благодаря которому можно запускать многие команды npm — пакетного менеджера Node.js. 1. Демонстрация 2. Недостатки Баги. Не запускается ряд команд. 2. Эмуляция терминала прямо в Sublime Text Общая оценка Все решения хорошие, пользуюсь ими, но полностью внешние терминалы они не заменяют. 1. Glue 1. Оценка Использую иногда. 2. Демонстрация 3. Установка и настройка Скачиваем плагин через Package Control → В открытом файле проекта Ctrl+Shift+P → Glue - Launch. Или же кликаете правой кнопкой мыши по папке в сайдбаре, в выпадающем меню выбираете Open Glue Terminal. Откроется quick panel, куда следует вводить команды: Появится файл terminal.glue. Без него никак, если мешает, можете добавить расширение glue в .gitignore, .hgignore или другой файл, который используется для игнорирования директорий/файлов в Вашей системе контроля версий. Чтобы в выводе была хоть какая-то подсветка, скачиваем плагин PowerShell → настраиваем для расширения glue синтаксис PowerShell. 4. Достоинства Не нужно выходить из Sublime Text, чтобы запускать команды, Достаточно многофункциональный плагин, Удобнее осуществлять навигацию по output, если тот большой, во вкладке, нежели в консоли. 5. Недостатки Разработка прекращена, шанс, что ответят на Ваш багрепорт, минимален, А багов, которые не воспроизводятся в других терминалах, достаточно. Так, не рекомендовал бы пушить изменения Git через Glue. Лимиты. Cash в Glue не запустишь. 6. Дополнительные ссылки Обзор Glue, Собственные команды Glue, Инструкция по созданию и использованию алиасов в Glue. 2. SublimeREPL Позволяет запускать REPL консоль для многих языков программирования во вкладке Sublime Text. В примере этого ответа написано, как настроить SublimeREPL для PowerShell. 1. Оценка Пользуюсь часто, но иногда вынужден прибегать к другим терминалам. 2. Демонстрация 3. Установка и настройка Помимо самого SublimeREPL устанавливаем также плагины Suricate и PowerShell для настройки команды SublimeREPL и подсветки синтаксиса соответственно. Инструкция по настройке команд в Suricate. Ctrl+Shift+P → SublimeREPL: PowerShell → если у Вас русская версия операционной системы, может вылезти всплывающее окно с примерно следующей ошибкой: error: UnicodeDecodeError('utf-8', b'C:\\Users\\\x8a\xae\xe2', 9, 10, 'invalid start byte') В таком случае перейдите в файл Default.suricate-profile (как — см. инструкцию, всё, что в ней есть, я буду опускать в данном ответе) → и вставьте следующий json-массив. Не путайтесь в JSON-синтаксисе, следите за правильной расстановкой кавычек, скобок и запятых. // SublimeREPL PowerShell "sublime_repl_powershell": { "caption": "SublimeREPL: PowerShell", "keys": ["super+alt+p"], "call": "sublime.repl_open", "args": { "type": "powershell", "encoding": "utf8", "cmd": ["powershell", "-"], "cwd": "$file_path", "external_id": "powershell", "syntax": "Packages/PowerShell/Support/PowerShellSyntax.tmLanguage" } }, 4. Параметры аргументов type — тип. Означает, что во вкладке запустится консоль PowerShell, а не какая-либо другая вроде Python или Node. encoding — кодировка. cmd — запускаем PowerShell в консоли Windows. cwd — указываем системную переменную. $file_path означает, что SublimeREPL PowerShell запустится в папке файла, находясь в котором мы запустили SublimeREPL PowerShell. external_id — Во-первых, данным параметром определяется, как будет называться вкладка с PowerShell. Если оставить параметру пустое значение, "external_id": "", то во вкладке будет указан полный путь к файлу powershell.exe: Мы назвали вкладку powershell, но можно по-любому. Если подставите значение sashatriumph, ничего не должно поломаться: Во-вторых, значение параметра external_id является именем файла, где хранится история команд, когда-либо вводимых Вами в SublimeREPL PowerShell. Файл c расширением .db располагается по пути Packages/User/.SublimeREPLHistory. syntax — относительный путь к файлу синтаксиса для подсветки вкладки SublimeREPL PowerShell, начиная с Packages. 5. Достоинства Не нужно выходить из Sublime Text, чтобы запускать команды, Удобнее осуществлять навигацию по output, если тот большой, во вкладке, нежели в консоли. Особенно нравится, что запоминаются все команды, которые когда-либо вводили. 6. Недостатки Кодировки. Если приходится работать не только с английскими символами, ещё замучаетесь бороться с багами. Разработка прекращена, шанс, что ответят на Ваш багрепорт, минимален, Не всё, что работает в PowerShell, работает в SublimeREPL PowerShell. Например, Cash в Glue не запустишь. SublimeREPL PowerShell не получится заменить терминал полноценно. 7. Дополнительная ссылка Документация SublimeREPL. 3. Terminality В примере показан вывод для Python, но можно использовать как консоль и для других языков программирования, включая отсутствующие по умолчанию в плагине. 1. Оценка Использую для обучения Python и PHP. 2. Демонстрация 3. Установка и настройка Загружаем плагин через Package Control → открываем файл hangman.py, вывод из которого собираемся осуществить, → Ctrl+Shift+P → Terminality: Browse Commands... → Run hangman.py — Run hangman.py as Python 2.7 document → видим результат в новой вкладке, включая время, потраченное на компиляцию, в сантисекундах. Обратите внимание, что пунктом меню Run hangman.py as Python3 запускается команда python3, при выборе Run hangman.py — команда python. Даже когда у Вас установлен Python 3, а не Python 2, если исполняемый файл Python называется python.exe, а не python3.exe, выбирайте Run hangman.py — Run hangman.py as Python 2.7 document. 4. Достоинства Не нужно выходить из Sublime Text, чтобы запускать команды, Удобнее осуществлять навигацию по output, если тот большой, во вкладке, нежели в консоли. Активно поддерживается разработчиками. 5. Недостатки Некоторые баги, которые не воспроизводятся во внешних терминалах. «Although Terminality can run many commands, it is not gurranteed that it can be used for all commands». 6. Дополнительные ссылки Репозиторий плагина, где описываются его возможности, Инструкция по настройке Terminality для не настроенных в плагине нативно языков программирования на примере PHP. 3. Запуск из Sublime Text внешних терминалов Достоинства и недостатки относятся уже к вызываемым в Sublime Text терминалам, а не самому Sublime Text. 1. Консоль/GNOME Terminal 1. Установка и настройка Устанавливаем плагин Suricate. Ctrl+Shift+P → Suricate: Open Terminal Here... → откроется новое окно с консолью для Windows и GNOME Terminal для Linux соответственно в директории с тем файлом, который был у Вас открыт, когда запускали терминал. 2. Параметры и их значения Как выглядит конфигурационный файл Suricate: // Open terminal. "open_terminal_here": { "call": "Suricate.lib.process.spawn", "caption": "Open Terminal Here...", "flags": "Windows|Linux", "args.windows": {"cmd": ["start", "cmd.exe"], "working_dir": "${file_path}"}, "args.linux": {"cmd": ["gnome-terminal"], "working_dir": "${file_path}"}, }, (В оригинальном массиве также есть параметры/значения "group": "launch", |IsFile, "context_menu": true, каковые я опустил в силу того, что считаю их излишними.) flags — параметр, при помощи которого можно задать различные аргументы для операционных систем или систем управления версиями. args.windows и args.linux — параметры запуска терминалов Windows и Linux. Дополнительная ссылка См. данный ответ и ссылки в его конце 2. Запуск любого предпочтительного терминала Для примера возьмём, как запустить Git Bash из Sublime Text. 1. Установка и настройка Устанавливаем плагин Suricate → в файл Default.suricate-profile добавляем следующий код: // Запустить Git Bash "git-bash": { "call": "Suricate.lib.process.spawn", "args.windows": { "cmd": ["C:\\Program Files\\Git\\git-bash.exe"], "working_dir": "${file_path}" }, "caption": "Git Bash", "keys": ["+super+keypad3"], }, Ctrl+Shift+P → Suricate: Git Bash → должен открыться Git Bash в директории с тем файлом, который был у Вас открыт, когда запускали Git Bash из Sublime Text. 2. Дополнительная ссылка См. данный ответ и ссылки в его конце 3. Плагин Terminal 1. Описание Кроссплатформенный плагин, позволяющий открывать из Sublime Text любой терминал, который лично Вы считаете наиболее предпочтительным. В Windows по умолчанию запускается PowerShell. После установки плагина доступны 3 варианта запуска: Из command palette, Из контекстного меню сайдбара, Шорткатом. Многим пользователям не нравится, что задействуется сочетание, по умолчанию используемое для переоткрытия последней закрытой вкладки, можете перезаписать шорткат в файле пользовательского кеймапа. Вызываются две команды: open_terminal — открывает терминал в папке, где лежит файл, вкладка с которым была открыта, когда запускали терминал. open_terminal_project_folder — возможно, работает некорректно. Актуальное поведение: Если Вы запустили команду, из файла, который находится в верхней папке Вашего сайдбара или её подпапках, терминал запустится в этой верхней папке. Например, мой сайдбар: Когда я запускаю open_terminal_project_folder, например, из файла E:\Киролайна\SashaFolder\SashaFile.txt, терминал откроется в E:\Киролайна. Но когда Вы запускаете команду из файла, не имеющего отношения к верхней папке Вашего сайдбара — в моём случае E:\Киролайна, — поведение команды open_terminal_project_folder аналогично поведению open_terminal. 2. Настройка Вы можете указывать параметры запуска Вашего терминала. Положим, хотите всегда запускать консольный эмулятор cmder только из директории E:\SashaSublime. Для упрощения работы с настройками Sublime Text скачиваем плагин Preferences Editor. Ctrl+Shift+P → Edit Preferences: Edit Settings... → Terminal → terminal → в открывшуюся quick panel вставляете путь к исполняемому файлу cmder.exe вместе с именем файла, например, E:\Chocolatey\tools\cmder\Cmder.exe → Enter. Далее Ctrl+Shift+P → Edit Preferences: Edit Settings... → Terminal → parameters → между квадратными скобками вставляем "/START", "E:\\SashaSublime" → Enter. Обратите внимание, что если значения заключены в [квадратные скобки], необходимо экранировать слэши: E:\Chocolatey\tools\cmder\Cmder.exe, но E:\\SashaSublime. Теперь после запуска любой из команд — open_terminal либо open_terminal_project_folder должен открыться Cmder.exe в папке E:\SashaSublime. Также предусмотрена возможность одним шорткатом запускать один терминал со своими параметрами, вторым хоткеем запускать другой терминал с другими параметрами и т. д. Читаем здесь. 3. Дополнительные ссылки Краткое описание плагина Terminal в книге «Sublime Text Power User», Репозиторий плагина на GitHub 4. ConEmu Для лучшей, по мнению пользователей англоязычного Stack Overflow, консоли для Windows есть свой плагин. См. также плагин для Cmder — немного изменённого ConEmu. 1. Описание По умолчанию осуществляется запуск PowerShell в оболочке ConEmu. Как и в плагине Terminal, ConEmu можно запустить из command palette, контекстного меню сайдбара или шорткатом. open_conemu_here — открывает ConEmu в папке, где лежит файл, вкладка с которым была открыта, когда запускали ConEmu. open_conemu_project — возможно, работает некорректно. Всегда открывает ConEmu в верхней папке сайдбара, в моём случае (см. п. 3.3) это E:\Киролайна. 2. Недостатки Разработчик перешёл на MacOS, плагин больше не поддерживается. Баги. я пофиксил, что нашёл, но далеко не факт, что их больше не осталось. 3. Дополнительные ссылки Альтернативный терминал для Windows — статья на Хабрахабре, Официальный сайт ConEmu, Документация ConEmu. 4. Обратное решение — вывод во внешнюю консоль 1. Console Exec 1. Оценка Пользуюсь вместо дефолтных Build System. 2. Описание Плагин выводит результаты Build System во внешнюю консоль, а не встроенную Sublime Text. Это может понадобиться по ряду причин. Если после вывода требуется вводить что-то ещё в консоль , — дефолтным механизмом Build System без дополнительных надстроек не обойтись. Установив же Console Exec и добавив в файл Build System всего одну дополнительную строку, Вы можете и дальше вводить команды. Если пользуетесь плагином Build Next, когда в выводе нет ошибок, встроенная панель Build System автоматически закрывается. Использование внешней панели средствами Console Exec избавляет от данной проблемы. Встроенная панель не поддерживает некоторые средства программирования как Pyglet. В панели Build System неудобна навигация. Увеличишь панель Build System — не будет видно содержимого вкладок, уменьшишь — вывода в панель. Выводя результаты во внешнюю консоль, при закрытии Sublime Text внешняя консоль остаётся открытой — дополнительное удобство. 3. Демонстрация 4. Настройка После установки плагина достаточно добавить в файл Build System одну дополнительную строку: "target": "console_exec" Пример для Python. Tools → Builds System → New Build System... → вставляем следующий код и сохраняем файл, например, под именем SashaPythonExec.sublime-build: { "cmd": ["python", "-u", "$file"], "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)", "selector": "source.python", "target": "console_exec" } Как создавать и настроить автоматический выбор Build System, подробно рассмотрено по дополнительным ссылкам. Во вкладке со скриптом на Python Ctrl+Shift+P → Build With: SashaPythonExec → смотрим результат. 5. Дополнительные ссылки Документация по использованию Build System в Sublime Text, Описание Build System в книге «Sublime Text Power User», Некоторые готовые Build System для компьютерных языков и инструментов программирования, Настройка автоматического выбора Build System. 2. Send to Shell В Sublime Text существуют плагины, отправляющие во внешний терминал выделенный или скопированный текст, как SendText и SendREPL. Тот же принцип действия у плагина Send to Shell, отправляющего скопированный текст в IPython — интерактивную оболочку для Python, составляющую Jupyter. 1. Демонстрация 2. Установка Как настроить плагин для отправки скопированного текста на ConEmu в режиме PowerShell. Скачиваем и устанавливаем последнюю версию Python, если Python ещё не установлен в системе. Устанавливаем Jupyter, проще всего, запустив в терминале команду pip install jupyter. Устанавливаем через Package Control PyWin32 — набор расширений Python для доступа ко многим функциям Windows API. Устанавливаем через Package Control плагин Preferences Editor для упрощения работы с файлами настроек Sublime Text. Устанавливаем через Package Control плагин Send to Shell. 3. Настройка Задаём системную переменную PATH, указав в качестве значения путь к файлу ConEmu.exe, для меня это C:\Program Files\ConEmu. Запускаем ConEmu → Super+Alt+P → Startup → задаём параметру Specifed named task значение {Shells::PowerShell}: В Sublime Text 3 Ctrl+Shift+P → Edit Preferences: Edit Settings... → SendToShell → powershell_startup → в открывшееся поле вместо powershell вписываем conemu. Ctrl+Shift+P → Edit Preferences: Edit Settings... → SendToShell → window_title → в открывшееся поле вместо Windows PowerShell вписываем заголовок вкладки ConEmu: у меня это powershell (Admin). Опционально предлагаю установить плагин CopyOnSelect, — пусть по первому времени он вызвать неудобства, — копирующий в буфер обмена выделенный текст. Задержка между выделением текста и его копированием в данном плагине составляет секунду, и автор не рекомендует её сильно уменьшать из-за возможных проблем с работой Clipboard-менеджеров. Настройка окончена. Выделяем кусок скрипта на Python для отправки в ConEmu → копируем его (а с плагином CopyOnSelect достаточно только выделить) → запускаем команду sendtoshell {"how": "paste_selection"}, — по умолчанию сочетанием клавиш Ctrl+Shift+Enter, — в ConEmu пишем команду ipython, а затем %paste. Можно было, конечно, написать плагин так, чтобы пользователь совершал поменьше действий. 4. Недостатки Баги в установке связи плагина с терминалом. 5. Дополнительные ссылки Оболочка IPython как инструмент системного администратора (python freebsd shell), IPython: замена стандартного Python shell. 5. Поиск плагинов Если описанные в обзоре плагины не удовлетворяют Вашим задачам, помимо обычного поиска в Google порекомендовал бы осуществить поиск примерно по следующим ключевым словам и меткам на сайте Package Control: terminal, build system, console, repl, shell.

Наибольшее число палиндром, которое является произведением двух простых пятизначных чисел

#android #циклы #простые_числа


Делал приложение по ТЗ из одной компании. Сделал андроид-аппку, получил результат
на эмуляторе, вроде же верный. Но HR просто отписалась, что ответ который выдало мое
приложение неверен.
Айчары люди довольно занятые, потому редко кто может указать на ошибку, а навязываться
после отказа - дело очень неблагодарное. Но все же хочется хоть для себя выполнить
задание до конца.

Из требований было:


  Напишите программу, которая возвращает наибольшее число палиндром, которое
  является произведением двух простых пятизначных чисел, а также возвращает
  сами сомножители.
  Простое число - это натуральное число, которое делится нацело только на 1 и
  на себя само (2, 3, 5, 7, 11, …)
  Палиндром – строка, которая читается одинаково в обоих направлениях
  (например ABBA)


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

Потому решил использовать циклы для сопоставления и отсеивания.

Вот код моего андроид-приложения:

MainActivity:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private int maxNum = 99999;
    private int minNum = 10000;

    private int divNumMax = 0;
    private int palind;

    private TextView tv1;
    private TextView tv2;
    private TextView tv3;
    private TextView tv4;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv1 = (TextView) findViewById(R.id.textView1);
        tv2 = (TextView) findViewById(R.id.textView2);
        tv3 = (TextView) findViewById(R.id.textView3);
        tv4 = (TextView) findViewById(R.id.textView4);

        Button btnStart = (Button) findViewById(R.id.button);
        btnStart.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {

        divNumMax = (int) Math.sqrt(maxNum);

        int fPM;
        int sPM;
        boolean isNotPalind;

        fPM = findMaxPrimeNumber(maxNum);
        sPM = findMaxPrimeNumber(fPM - 2);
        isNotPalind = findPalindrome(fPM, sPM);

        while (isNotPalind) {

            if (sPM <= fPM && sPM > minNum) {
                sPM = findMaxPrimeNumber(sPM - 2);
                isNotPalind = findPalindrome(fPM, sPM);

            } else if (sPM <= minNum) {
                fPM = findMaxPrimeNumber(fPM - 2);
                sPM = fPM;
            }

            tv2.setText("1-st primary number: " + fPM);
            tv3.setText("2-nd primary number: " + sPM);
            tv4.setText("1-st * 2-nd = " + palind);

        }
    }


    private int findMaxPrimeNumber(int maxNumPre) {
        int i;
        int j;
        int z;
        int maxNumNew;

        for (i = maxNumPre; i >= minNum; i = i - 2) {

            for (j = 3; j <= divNumMax; j++) {

                z = i % j;

                if (z == 0 && j <= divNumMax) {
                    break;

                } else if (z != 0 && j == divNumMax) {
                    maxNumNew = i;
                    return maxNumNew;

                }
            }

        }
        return 10000;
    }


    private boolean findPalindrome(int firstPrime, int secondPrime) {

        int resultOfMath = firstPrime * secondPrime;

        String ltrResult = Integer.toString(resultOfMath);
        String rtlResult = new StringBuffer(ltrResult).reverse().toString();

        if (ltrResult.equals(rtlResult)) {

            palind = resultOfMath;
            return false;

        } else {
            return true;
        }
    }
}


Скриншот полученного результата на эмуляторе:



Ломаю голову где ошибся, что упустил. Не прошу делать за меня ТЗ, но не хочу оставлять
позади какую-то неразобранную проблемму.
    


Ответы

Ответ 1



Ваше целое несколько раз завернулось вокруг максимального значения int - 2,147,483,647. Проверьте: 99923 * 87541 = 8 747 359 343 А также: На какую цифру должно заканчиваться произведение Ваших двух простых чисел?

Ответ 2



решето работает отлично, ранее искал все простые числа в диапазоне 0- 10 000 000 ушло примерно 15 секунд на планшете. главное правильно написать алгоритм. возможно я не верно понял ваш алгоритм (прошу исправить меня) почему второй цикл идет по увеличению параметра, а не от большего к меньшему? for (j = 3; j <= divNumMax; j++) { есть нюанс: рассмотрим ту же задачу, но в диапазоне 0-15, пока отбросим условие палиндрома (здесь оно не играет роли). a = 13; b = 2; a*b = 26 но есть и другие простые числа произведение которых даст значительно больше результат? 11*13 > 26

Ответ 3



Вот правильный ответ на задачу, также встречал на собесе: палиндром - 999949999 множитель1 - 33211 множитель2 - 30109 Реализовал алгоритм так: Метод поиска наибольшего палиндрома (на входе список простых чисел) static void palindrome(ArrayList primeNumbers) { long palindrome = 0; long multiplier1 = 0; long multiplier2 = 0; for (int j = 0; j < primeNumbers.size(); j++) { for (int k = 0; k < primeNumbers.size(); k++) { long i = (long) primeNumbers.get(j) * (long) primeNumbers.get(k); if (palindromeCheck(i)) { if (i > palindrome) { palindrome = i; multiplier1 = primeNumbers.get(j); multiplier2 = primeNumbers.get(k); } } } } System.out.println("palindrome = " + palindrome + "\nmultiplier1 = " + multiplier1 + "\nmultiplier2 = " + multiplier2); } Метод поиска простых чисел (на входе максимальное и минимальное значения из проверяемого диапазона чисел): static ArrayList eratosthenesPrimeNumbers(int max, int min) { ArrayList primeNumbers = new ArrayList<>(); boolean[] array = new boolean[max]; for (int i = 2; Math.pow(i, 2) <= max; i++) { if (!array[i]) { for (int j = (int) Math.pow(i, 2); j < max; j += i) { array[j] = true; } } } for (int i = max - 1; i >= min; i--) { if (!array[i]) { primeNumbers.add(i); } } return primeNumbers; } Проверка на то, что найденное число является палиндромом (на входе проверяемое число): static boolean palindromeCheck(long i) { char[] palindrome = String.valueOf(i).toCharArray(); int fromBegin = 0; int fromEnd = palindrome.length - 1; while (fromBegin < fromEnd) { if (palindrome[fromBegin] == palindrome[fromEnd]) { fromBegin++; fromEnd--; } else return false; } return true; } Да и еще забыл написать, что эти методы надо вызывать :) У меня это сделано так: public class Main { static final int MAX_MULTIPLIER = 99999; static final int MIN_MULTIPLIER = 10000; public static void main(String[] args) { ArrayList primeNumbers2 = new ArrayList<>(eratosthenesPrimeNumbers(MAX_MULTIPLIER, MIN_MULTIPLIER)); palindrome(primeNumbers2); } и дальше реализация методов...

Ответ 4



Немного вник в алгоритм. По моему, он работает неправильно уже здесь: while (isNotPalind) { if (sPM <= fPM && sPM > minNum) { sPM = findMaxPrimeNumber(sPM - 2); isNotPalind = findPalindrome(fPM, sPM); } else if (sPM <= minNum) { fPM = findMaxPrimeNumber(fPM - 2); sPM = fPM; } } Получается ты выведешь первый встречный палиндром, но нет гарантии, что он будет максимальный. Возьмем отвлеченный от этого пример прогонки от 10 до 1 возможных произведений всех чисел. По твоему алгоритму идем по 1-му кругу: 10*10, 10*9 , 10*8, 10*7.... <- и сразу выводим первый попавшийся палиндром далее второй круг: 9*9, 9*8, 9*7... <- или уж тут сразу выводим первый попавшийся палиндром далее третий: 8*8, 8*7, 8*6... И так далее... Допустим на 1-ом круге 10*2 - это палиндром (гипотетически!) Также допустим на 2-ом круге 9*8 - это тоже палиндром (гипотетически!) Но твоя программа выведет 10*2 (несмотря на то что 9*8 больше чем 10*2) То есть первое попавшееся - это не вариант. Надеюсь автор меня понял и поправит если я не прав.

Ответ 5



условие задачи подразумевало произведение двух простых пятизначных чисел. алгоритм работает для двух, трех, четырехзначных чисел. но в упор отказывается работать для 5-ти. в чем тут ошибка? public class Palindrome { private static final boolean reverse(long value) { String str = String.valueOf(value); return str.equals(new StringBuilder(str).reverse().toString()); } private static final boolean isPrime(int n) { int i; for (i = 2; i <= n / 2; i++) { if (n % i == 0) { return false; } } return true; } public static void main(String[] args) { int i = 0; int maxPrimeNumber = 99971; int minPrimeNumber = 10007; outer: for (i = maxPrimeNumber; i >= minPrimeNumber; i--) { for (int j = maxPrimeNumber; j >= minPrimeNumber; j--) { if (isPrime(i) && isPrime(j)) { long product = j * i; if (reverse(product)) { System.out.printf("%d * %d = %d%n", i, j, product); break outer; } } } } } }

Как сверстать блок с линиями отходящими от центральной картинки?

#html #css #вёрстка #svg #адаптивная_верстка


Возможно, кто-то сталкивался с подобными блоками?



Не представляю, как это можно реализовать. Вряд ли получится с помощью абсолютного
позиционирования адаптивно сверстать такое. 

UPD1: Сложность заключается в верстке линий, отходящих от центральной картинки, в
верстке блоков текста ничего сложного для меня нет.
    


Ответы

Ответ 1



Вариант с применением двух изображений При этом решение используется pattern для добавления второго круглого изображения в центре. Решение адаптивно, вёрстка не сломается при изменении размера окна браузера и при просмотре на любом гаджете. Фоновое изображение добавляется с помощью команды: Затемняется командой - opacity="0.45" Позиционируется координатами - x и y Изображение полностью заполняет родительский блок
и может быть вставлено, как самостоятельный элемент в любое место веб страницы. Круглое изображение добавляется поверх фонового изображения с помощью Ниже полный код приложения: .container { width:100%; height:100%; } .s0{ fill:none; stroke-width:2; stroke:#45228B; }
Быстрый старт Низкая стоимость входа в бизнес Система обучения вашего персонала и помощь в его подборе Простая, проверенная бизнес модель Бизнес - любимое дело
Вариант с применением фильтров Если выбранное изображение устраивает вас по содержанию, но в связи с требованиями дизайна нужно сменить цвет оттенка фона или цвет фигур, то совсем не обязательно дорабатывать картинку в фотошопе, можно её перекрасить с помощью комбинации фильтров: feflood, feComposite, feBlend Техника применения этих фильтров подробно объясняется в топике на нашем сайте #1 Вариант с покраской фигур В фильтре применяется оператор mode="lighten" .container { width:100%; height:100%; } .s0{ fill:none; stroke-width:2; stroke:#D57700; }
Быстрый старт Низкая стоимость входа в бизнес Система обучения вашего персонала и помощь в его подборе Простая, проверенная бизнес модель Бизнес - любимое дело
#2 Вариант с покраской фона В фильтре применяется оператор mode="darken" .container { width:100%; height:100%; } .s0{ fill:none; stroke-width:2; stroke:#E1E1E1; }
Быстрый старт Низкая стоимость входа в бизнес Система обучения вашего персонала и помощь в его подборе Простая, проверенная бизнес модель Бизнес - любимое дело


Ответ 2



Надеюсь работники офисов не будут на меня в обиде за беззлобную шутку-картинку, демонстрирующую их тяжкий повседневный труд. Это скорее сочувствие. Может быть вы улыбнетесь, глядя на эту картинку и вам станет легче переносить самодура-начальника в повседневности. Чтобы получить адаптивное приложение, которое будет работать во всех современных браузерах, необходимо выполнить следующие шаги: Загружаем выбранную картинку в векторный редактор и устанавливаем размеры svg полотна равные ширине и высоте растрового изображения В векторном редакторе с помощью инструмента - Рисовать кривые Безье добавляем нужные контуры линий для размещения поясняющего текста Сохраняем файл в формате SVG и прогоняем его через оптимизатор для получения чистого кода без лишнего кода от Inkscape Чтобы получить центральную, круглую часть изображения более светлую по сравнению с остальным фоном изображения, применяем комбинированную маску, где центральный круг имеет атрибут fill="white", что делает его полностью прозрачным. rect имеет более темную закраску fill="#978300", поэтому фон будет затемненным. Добавляем текст Ниже полный код: .container { width:100%; height:100%; } .s0{ fill:none; stroke-width:2; stroke:#45228B; }
Быстрый старт Низкая стоимость входа в бизнес Система обучения вашего персонала и помощь в его подборе Простая, проверенная бизнес модель
Та же техника реализации с другой картинкой: .container { width:100%; height:100%; } .s0{ fill:none; stroke-width:2; stroke:#45228B; }
Быстрый старт Низкая стоимость входа в бизнес Система обучения вашего персонала и помощь в его подборе Простая, проверенная бизнес модель


Ответ 3



Вот SVG вариант. Я умышленно ставлю вьюбокс наполовину в отрицательную область (viewbox="-100 -100 200 200"), чтобы координата 0,0 была в центре картинки, так легче из головы брать точки для полилиний без дополнительной арифметики. hello row 1 row 2

Ответ 4



Вариант с помощью псевдоэлемента и CSS. Вместо after можно использовать SVG элемент. .title { position: relative; width: 300px; border-bottom: 1.5px solid black; padding: 5px 10px; } .title::after { position: absolute; right: 16px; bottom: -69px; width: 100%; height: 1.5px; background-color: black; transform: translateX(100%) rotate(25deg); content: ""; }
lorem ipsum


Как узнать размер базы данных PostgreSQL?

#база_данных #postgresql


Есть база PostgreSQL base, пользователь postgres. Как одной командой, не используя
скриптов, получить размер базы?    


Ответы

Ответ 1



Войти в интерактивный терминал: $ sudo -u postgres psql Выполнить запрос: # select pg_database_size('base');

Ответ 2



В человеческом виде размер базы покажет обёртка pg_size_pretty SELECT pg_size_pretty( pg_database_size( 'sample_db' ) ); pg_size_pretty ---------------- 36 GB Таким же макаром можно посмотреть и размер таблицы (с индексами) SELECT pg_size_pretty( pg_total_relation_size( 'table' ) ); pg_size_pretty ---------------- 6341 MB Если нужно без индексов, тогда запрос другой: # SELECT pg_size_pretty( pg_relation_size( 'table' ) ); pg_size_pretty ---------------- 1341 MB

Нейронные сети на Python для “чайника” [закрыт]

#python #книги #нейронные_сети


Часто встречаю такое понятие, как нейронные сети и, учитывая еще и тот факт, что
потихоньку изучаю Python, то возникла потребность "что-то эдакое" попробовать самому
написать, но более менее встречающаяся литература в сети, слишком "тверда и не по зубам"
для меня. А ведь так захватывающе - попробовать!
Вопрос: есть ли ресурс, где есть простенькие примеры на Python, для "блондинки с
чайником в руках"? В общем буду признателен всем, кто может посодействовать.    


Ответы

Ответ 1



Есть куча книг по машинному обучению и нейронным сетям. Machine Learning: an Algorithmic Perspective - пример того, что Вам нужно. И почему у нас принято только о нейронных сетях вспоминать? Но в этой книге есть среди прочих пример реализации нейронной сети на Python. Посмотрите пост на хабре с практическим примером. Вам полезно ещё познакомиться с numpy. Есть Python-библиотеки, в которых много чего уже написано. Например, всем известный PyBrain. Еще некоторые: ffnet neurolab PyNN pylibneural Есть хорошая библиотека машинного обучения, которую использую сам, но она не содержит нейронных сетей.

Ответ 2



Почитайте книгу "Программируем коллективный разум", думаю вам понравиться.

Ответ 3



Для начинающих появился бесплатный курс на Stepic Нейронные сети в данном курсе используется язык python.

Лучший метод оценки производительности труда программиста? [закрыт]

#работа #производительность


Вариант 1. Количество строк кода в единицу времени. Плохой вариант. Все равно что
измерять готовность самолета по его массе. Не учитывает китайский стиль.
Вариант 2. Работает/не работает. Слишком примитивно, не учитывает оптимизацию. Бомбейская
школа программистов была здесь.
Вариант 3. Программист или его коллега сами оценивает работу друг друга исходя из
собственного опыта. Зависит от программиста. Не объективно, но может принести результат
или дело кончится холиваром.
Вариант 4. Оценка бесполезна для процесса и не стоит тратить на нее время.
Вариант 5. Быстрая микроценка проделанной за день работы. Не дает общей картины.
Кто каким образом делает это? Я использую вариант 5 + вариант 1 без учета копипаста,
китайского кода и с учетом комментариев, получается около 5-20 кБайт в день в зависимости
от части над которой идет работа. Какие еще есть варианты?    


Ответы

Ответ 1



Вариант 6. Ежедневные 5-минутные тесты/головоломки для программистов. Вроде заданий из инструментальных тестов на навыки. Особенно с утра. Плюсы: объективная оценка хотя бы состояния человека перед началом дня; прокачка мозга на програмирование, при регулярном ежедневном применении польза будет немала. Минусы: где брать тесты, постоянно новые, интересные, адекватные работе и навыкам. Возможно, тесты придётся покупать; метрика оторвана от контекста работы.

Ответ 2



Хорошей общеизвестной метрики нет (и вряд ли может быть), но никто не мешает вам установить локальную для себя метрику продуктивности. Вы же подсознательно знаете, сделали вы сегодня больше, чем вчера, или меньше. Метрика производительности такого рода имеет смысл только в контексте проекта, а не разработчика. Рекомендую ознакомиться с информацией по поводу Теории Ограничений и по поводу ее распространения на Agile процессы. Фактически, вашим вариантом номер 5 вы частично переизобрели Daily Scrum Meeting.

Ответ 3



В нашей команде уже достаточно давно используется следующая схема: Команда разделена на группы по 3-4 человека, в каждой группе есть главный (обычно более опытный сотрудник). Его задачи: раздача и контроль выполнения заданий, он тесно связан с процессом разработки (практически каждой задачи в его группе), поэтому в курсе прогресса review документации и кода оценка качества выполнения задач и эффективности членов его группы. Тесное взаимодействие людей одной группы практически гарантирует адекватные оценки со стороны лидера группы. Лидеры групп репортят менеджеру команды. Последний не занимается решением технических вопросов, это обязанности "лидеров групп", его основные обязанности - это решение организационных вопросов. т.е. наша схема склоняется к варианту 3

Ответ 4



Абсолютную шкалу построить невозможно. Не существует идеального программиста, ритм работы которого на любой задаче был бы оптимальным с точки зрения как скорости разработки, так и качества кода. Но это не значит, что производительность вообще не поддаётся измерению. Я использую для этого относительную метрику. Перед началом каждого участка работы я, исходя из опыта, делаю более-менее реалистичные предположения о том, когда закончу, а после сравниваю их с реально затраченным временем. Если в процессе не возникло никаких форс-мажоров, но была существенная задержка, то значит производительность была низкой. Количество лишних часов красноречиво говорит о том, насколько низкой. Но бывает и наоборот. Задача решается быстрее, чем планировалось, и при этом я ясно понимаю, что решил задачу именно так, как и планировал - ничего в процессе не упростил. В этом случае я делаю вывод о том, что мне нужно пересмотреть собственные представления о своих возможностях в лучшую сторону - в действительности я круче, чем думаю о себе.

Как починить android.os.NetworkOnMainThreadException

#java #android #faq


Здравствуйте.  Пытаюсь сделать POST запрос на ajax страницу с помощью HttpURLConnection.
Сильно не пинайте, я только сегодня начал практиковать Java и Android. Тестю на API
22 (Intel x86). В обычном хроме та же страница нормально загружается. Logcat:

03-24 10:23:26.842 4679-4679/? I/art: Late-enabling -Xcheck:jni
03-24 10:23:27.402 4679-4679/com.gobonus.gobonus D/AndroidRuntime: Shutting down VM
03-24 10:23:27.427 4679-4679/com.gobonus.gobonus E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.gobonus.gobonus, PID: 4679    
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.gobonus.gobonus/com.gobonus.gobonus.WelcomeActivity}:
android.os.NetworkOnMainThreadException

    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2358)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2420)
    at android.app.ActivityThread.access$900(ActivityThread.java:154)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1321)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5294)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)
Caused by: android.os.NetworkOnMainThreadException
    at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1147)
    at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:110)
    at libcore.io.IoBridge.connectErrno(IoBridge.java:137)
    at libcore.io.IoBridge.connect(IoBridge.java:122)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:183)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:456)
    at java.net.Socket.connect(Socket.java:882)
    at com.android.okhttp.internal.Platform.connectSocket(Platform.java:174)
    at com.android.okhttp.Connection.connect(Connection.java:152)
    at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:276)
    at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:211)
    at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:382)
    at com.android.okhttp.internal.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:106)
    at com.android.okhttp.internal.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:217)
    at com.gobonus.gobonus.Request.(Request.java:65)
    at com.gobonus.gobonus.WelcomeActivity.onCreate(WelcomeActivity.java:15)
    at android.app.Activity.performCreate(Activity.java:5990)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2311)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2420) 
    at android.app.ActivityThread.access$900(ActivityThread.java:154) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1321) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:135) 
    at android.app.ActivityThread.main(ActivityThread.java:5294) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:372) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) 
    at 


com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699) 
    03-24 10:23:27.498 4679-4690/com.gobonus.gobonus W/art: Suspending all threads
took: 26.757ms
Request.java:


package com.gobonus.gobonus;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;


public class Request {

    private final String USER_AGENT = "GoBonus Android Client 1.0";
    private final String API_SERVER = "http://192.168.2.21";

    public String Content;


    public Request (String session_token, String uri, String params) {

        String urlParameters  = "session_token="+session_token+"&"+params; // url params
        byte[] postData       = new byte[0];

        System.setProperty("http.agent", USER_AGENT); // user agent truck

        // api = android.os.Build.VERSION_CODES.KITKAT) {
            postData = urlParameters.getBytes( StandardCharsets.UTF_8 );
        }
        else
            postData = urlParameters.getBytes(Charset.forName("UTF-8"));

        int    postDataLength = postData.length;
        URL    url            = null;

        try {
            url = new URL( API_SERVER + uri);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        HttpURLConnection conn= null;
        try {
            conn = (HttpURLConnection) url.openConnection();
        } catch (IOException e) {
            e.printStackTrace();
        }
        conn.setDoOutput( true );
        conn.setInstanceFollowRedirects( false );
        try {
            conn.setRequestMethod("POST");
        } catch (ProtocolException e) {
            e.printStackTrace();
        }
        conn.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty( "charset", "utf-8");
        conn.setRequestProperty( "Content-Length", Integer.toString( postDataLength ));

        conn.setUseCaches( false );
        try {
            DataOutputStream wr = new DataOutputStream( conn.getOutputStream());
            wr.write( postData );
            conn.connect();
            Content = ConvertData(conn);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    protected String ConvertData (HttpURLConnection url) throws IOException {
        // local variables
        String line;
        StringBuffer text = new StringBuffer();

        InputStreamReader in = new InputStreamReader((InputStream) url.getContent());
        BufferedReader buff = new BufferedReader(in);
        do {
            line = buff.readLine();
            text.append(line + "\n");
        } while (line != null);
        return text.toString();
    }

}



WelcomeActivity.java


package com.gobonus.gobonus;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class WelcomeActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView WebTest = (TextView) findViewById(R.id.webTest);
        WebTest.setText(new Request("123", "/ajax", "foo=bar").Content);
        setContentView(R.layout.activity_welcome);
    }

    public void LoginGo(View view) {
        Intent intent = new Intent(WelcomeActivity.this, LoginActivity.class);
        startActivity(intent);
    }
}


Манифест




    
    
    
    
    

    
        
            
                

                
            
        
        
            
        
    




Layout


    

        


Ответы

Ответ 1



Эксепшн NetworkOnMainThreadException говорит о том, что вы используете сетевые запросы в главном потоке, используйте AsyncTask для запуска запроса в отдельном от UI потока. И Метод setContentView, нужно вызывать до того, как будете обращаться к элементам разметки. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_welcome); TextView WebTest = (TextView) findViewById(R.id.webTest); WebTest.setText(new Request("123", "/ajax", "foo=bar").Content); } UPD Пример запроса через AsyncTask. Метод doInBackground выполняется в отдельном от UI потоке, после того, как вы выполнили запрос и получили ответ, ваши данные упадут в onPostExecute, который выполняется уже в потоке UI. Не обращайтесь к потоку UI в doInBackground, вызовет Exception. public class WelcomeActivity extends AppCompatActivity { TextView WebTest; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_welcome); WebTest = (TextView) findViewById(R.id.webTest); new AsyncRequest().execute("123", "/ajax", "foo=bar"); } class AsyncRequest extends AsyncTask{ @Override protected String doInBackground(String... arg) { return new Request(arg[0], arg[1], arg[2]).Content; } @Override protected void onPostExecute(String s) { super.onPostExecute(s); WebTest.setText(s); } } }

Упаковка ValueType при использовании IEnumerable

#c_sharp #массивы #.net


Допустим, имеется некий массив, например:

int[,] array = { { 1, 2, 3 }, { 4, 5, 6 } };


Все массивы реализуют IEnumerable (не generic), таким образом, при использовании
этого интерфейса все элементы будут упакованы?

Вопрос актуален, например, при использовании Linq-операций Cast() или OfType():

Console.WriteLine(string.Join(" " , array.Cast()));

    


Ответы

Ответ 1



Да, ситуация с многомерными массивами довольно печальная. Такой массив реализует IEnumerable, но не реализует IEnumerable. А это означает, что любое использование многомерного массива через "призму" IEnumerable приведет к упаковке каждого элемента, и использование метода Enumerable.Cast - не исключение. Вот простой бенчмарк (на основе BenchmarkDotNet), который показывает, что это действительно так: [MemoryDiagnoser] public class MultidimentionalAarrayTests { private int[,] m_multiArray = {{1, 2}, {3, 4}}; private int[] m_regularArray = {1, 2, 3, 4}; [Benchmark] public int MultiArrayLast() { return m_multiArray.Cast().Last(); } [Benchmark] public int RegularArrayLast() { return m_regularArray.Last(); } } Результат: Method | Mean | Error | StdDev | Gen 0 | Allocated | --------------------------- |------------:|----------:|----------:|-------:|----------:| MultiArrayLast | 1,166.97 ns | 23.229 ns | 51.473 ns | 0.0401 | 132 B | RegularArrayLast | 51.29 ns | 1.250 ns | 3.686 ns | - | 0 B | Мы тут видим кучку аллокаций: в первом случае - упакован каждый элемент, итератор в Cast, итератор в Last. Во втором случае нет аллокаций вообще, поскольку Last проверяет, что последовательность реализует IList (а одномерный массив его реализует) и сразу же возвращает последний элемент. Поскольку многомерные массивы не реализуют обобщенный IEnumerable, то заставить его сделать это самим мы не можем, но мы можем создать метод расширения, чтобы не использовать Enumerable.Cast: public static class MultiDimentionalArrayEx { public static IEnumerable AsEnumerable(this T[,] array) { foreach (var e in array) yield return e; } } Теперь мы можем добавить еще один бенчмарк, чтобы проверить результат: [Benchmark] public int MultiArrayWithAsEnumerable() { return m_multiArray.AsEnumerable().Last(); } И вот окончательный результат: Method | Mean | Error | StdDev | Gen 0 | Allocated | --------------------------- |------------:|-----------:|-----------:|-------:|----------:| MultiArrayLast | 1,115.45 ns | 31.0145 ns | 90.9603 ns | 0.0401 | 132 B | RegularArrayLast | 46.11 ns | 0.1826 ns | 0.1525 ns | - | 0 B | MultiArrayWithAsEnumerable | 161.74 ns | 3.2693 ns | 3.2109 ns | 0.0150 | 48 B | Здесь мы видим, что есть выделение в куче двух итераторов (одного для метода расширения и еще одного для Enumerable.Last), но нет упаковок самих элементов.

Ответ 2



При использовании необобщённого IEnumerable упаковки, конечно, не избежать. Но компилятор умный, и в некоторых случаях может обойтись без IEnumerable. Важный случай — это если объект, по которому производится перечисление, обладает открытым методом GetEnumerator с подходящей сигнатурой. В этом случае будет использован именно он.* Второй важный частный случай (и именно он у нас имеет место) — это массивы. Компилятор знает, как можно более эффективно обходить массивы, и иногда пользуется этим. Например, вот такая функция static int[,] array = ...; static void Test() { foreach (var val in array) Console.WriteLine(val); } скомпилировалась так, как будто она была написана следующим образом: int[,] array = Program.array; int upperBound = array.GetUpperBound(0); int upperBound2 = array.GetUpperBound(1); for (int i = array.GetLowerBound(0); i <= upperBound; i++) { for (int j = array.GetLowerBound(1); j <= upperBound2; j++) { Console.WriteLine(array[i, j]); } } Для случая Cast, кажется, оптимизатор не пытается улучшить код для массивов, и таки использует Cast. В коде Cast есть проверка на наличие типизированного варианта IEnumerable (и в этом случае упаковки бы не было), но массив его не поддерживает. Так что выполняется итерация по IEnumerable с упаковкой результатов. В последующих версиях языка, возможно, оптимизатор станет умнее (если разработчики сочтут этот случай важным). (Для недоверчивых, вот IL-код: // int[,] array = Program.array; IL_0000: ldsfld int32[0..., 0...] Test.Program::'array' IL_0005: stloc.0 // int upperBound = array.GetUpperBound(0); IL_0006: ldloc.0 IL_0007: ldc.i4.0 IL_0008: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) IL_000d: stloc.1 // int upperBound2 = array.GetUpperBound(1); IL_000e: ldloc.0 IL_000f: ldc.i4.1 IL_0010: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) IL_0015: stloc.2 // i = array.GetLowerBound(0) IL_0016: ldloc.0 IL_0017: ldc.i4.0 IL_0018: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) IL_001d: stloc.3 IL_001e: br.s IL_0048 // jump to outer loop check // loop start (head: IL_0048) // j = array.GetLowerBound(1) IL_0020: ldloc.0 IL_0021: ldc.i4.1 IL_0022: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) IL_0027: stloc.s 4 IL_0029: br.s IL_003f // jump to inner loop check // loop start (head: IL_003f) // array[i, j] IL_002b: ldloc.0 IL_002c: ldloc.3 IL_002d: ldloc.s 4 IL_002f: call instance int32 int32[0..., 0...]::Get(int32, int32) IL_0034: call void [mscorlib]System.Console::WriteLine(int32) // j++ IL_0039: ldloc.s 4 IL_003b: ldc.i4.1 IL_003c: add IL_003d: stloc.s 4 // j <= upperBound2 IL_003f: ldloc.s 4 IL_0041: ldloc.2 IL_0042: ble.s IL_002b // end loop // i++ IL_0044: ldloc.3 IL_0045: ldc.i4.1 IL_0046: add IL_0047: stloc.3 // i <= upperBound IL_0048: ldloc.3 IL_0049: ldloc.1 IL_004a: ble.s IL_0020 // end loop IL_004c: ret Проверяйте!) *Ссылка на документацию: Otherwise, determine whether the type X has an appropriate GetEnumerator method: и только после этого Otherwise, check for an enumerable interface: Это позволяет, в частности, при итерации по List итерировать не по интерфейсу IEnumerator, а по структуре List.Enumerator, и тем самым избежать упаковки этой структуры.