Страницы

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

среда, 3 октября 2018 г.

Подсчет минимального возможного количества замен у числа “x” по заданному алгоритму: x=m*n; x=m+n-2, где m и n - какие-то натуральные числа

Пояснение: Есть натуральное число x, его можно представить как произведение двух натуральных чисел m и n (x=m*n). Далее x нужно заменить на m+n-2 (x=m+n-2). И это все необходимо выполнять, пока x не станет равно 1
x может быть в пределах миллиарда
Пример: В программу поступило число 6.
6=3*2 3+2-2=3 6=6*1 6+1-2=5
3=3*1 3+1-2=2 5=5*1 5+1-2=4
2=2*1 2+1-2=1 - x=1, останавливаемся (до единицы мы дошли за 3 замены) 4=2*2 2+2-2=2

Мои попытки
from math import sqrt
def isint(n): return not(n%1)
def f(n): count = 0 while(True): x=sqrt(n) if(n<=1): return count if(isint(x)): n=x+x-2 else: x=int(x) while(isint(n/x)==False): x=x-1 if(x<=0): return count n=int((n/x)+x-2) count+=1 print('Минимальное кол-во попыток для числа 6 = ',f(6))
P.S. Мой алгоритм делает ошибки, но некоторые числа он все же считает


Ответ

Я питон не знаю... Но на С++ решение этой задачи - вот:
#include #include #include
using namespace std;
const int MAXSIZE = 1000000000;
unsigned char m[MAXSIZE+1];
int count(int x, int level = 0, int curmin = MAXSIZE) { if (level > curmin) return -1; // Отсечение - нет смысла лезть вглубь // при наличии более короткого решения if (x == 1) return 0; if (m[x]) { return m[x]; // Сохраненное значение } int res = MAXSIZE; for(int i = sqrt(x)+0.1; i >= 1; --i) { if (x%i) continue; int k = count(i+x/i-2, level+1, res); if (k < 0) continue; if (k < res) { res = k; } } return m[x] = res+1; };
int main(int argc, const char * argv[]) { int n = (argc > 1) ? atoi(argv[1]) : MAXSIZE; if (n > MAXSIZE) n = MAXSIZE; cout << n << ": " << count(n) << endl;
int cur = m[n]; while (n > 1) { for(int i = 1; i*i <= n; ++i) { if (n%i) continue; if (m[i+n/i-2] == cur-1) { n = i+n/i-2; --cur; cout << i << " "; break; } } } cout << endl; }
Как видите, на ideone решило миллиард за 0.04с :)
Ключевые моменты: 1. Перебор с отсечением 2. Начинаем со значений, близких к корню 3. Мемоизация
Кстати, до миллиона включительно самая длинная цепочка - 11, так что глубокой рекурсии явно не стоит ожидать.

Разница между catch, catch(Exception) и catch(Exception ex)

Допустим, я не планирую использовать переменную ex и мне надо, чтобы обрабатывалась любая ошибка.
try { ... } catch(Exception ex) { return; }
Надо ли в таком случае объявлять переменную ex?
Или можно сделать так:
try { ... } catch(Exception) { return; }
Или вообще вот так:
try { ... } catch { return; }
В чем разница и как правильнее?


Ответ

Переменную нужно объявлять, если в дальнейшем планируется её как-то использовать. Если важен только сам факт перехвата - достаточно указать всего лишь тип. Различие в catch(Exception) и пустом catch имеет место быть, если нужно перехватывать не CLS-совместимые исключения. Более подробнее об этом можно почитать на msdn. По ссылке как раз видно, что есть смысл и в таком коде:
catch(Exception) { ... } catch { ... }

Как писать в stdout и в файл одновременно?

Есть python скрипт:
import sys sys.stdout = open('my_log.log', 'w') print 'test'
Он пишет весь стандартный вывод в файл. Вопрос: как мне и писать в файл, и одновременно выводить на консоль?


Ответ

Как наколеночное решение, буквально выполняющее задачу, озвученную в вопросе: можно создать класс, который принимает два файловых объекта, и при записи в объект данного класса выполнять запись в оба файловых объекта.
import sys
class DoubleWrite: def __init__(self, file1, file2): self.file1 = file1 self.file2 = file2
def write(self, s): self.file1.write(s) self.file2.write(s)
def flush(self): self.file1.flush() self.file2.flush()
logfile = open('my_log.log', 'w') sys.stdout = DoubleWrite(sys.stdout, logfile)
print "test"
В целом, для логирования рекомендуется использовать уже существующие решения, в частности модуль logging
Обновление.
Для корректного перенаправления и последующего восстановления sys.stdout в Python 3 лучше использовать менеджер контекста contextlib.redirect_stdout. В стандартной библиотеке Python 2 такого менеджера контекста, к сожалению, нет.
Пример использования (для Python 3):
import sys from contextlib import redirect_stdout
class DoubleWrite: ...
with open('my_log.log', 'w') as logfile: with redirect_stdout(DoubleWrite(sys.stdout, logfile)): print('test')
После выхода из блока with redirect_stdout(...) значение sys.stdout восстановится.

Почему в переопределяемом (@Override) методе нельзя пробросить Exception?

Всем добрый вечер.
Столкнулся с интересной особенностью переопределяемых методов — исключения в них нельзя пробросить, только обработка внутри метода. Но почему? Хочется получить исчерпывающий ответ на этот вопрос.


Ответ

Есть два вида исключений в Java — checked и unchecked, подробнее можно почитать, например, в этой статье
Checked исключения проверяются на этапе компиляции приложения, и должны где-то отлавливаться (catch), а методы, которые выбрасывают такие исключения, должны иметь в сигнатуре тип исключения, который может быть выброшен (напр. void method() throws Exception). При переопределении (@Override) метода, в сигнатуре которого не указан throws, нельзя бросить checked-исключение, потому что компилятор не сможет его отследить. Нерабочий пример:
class A { void foo() {} }
class B extends A { @Override void foo() throws Exception {} }
A obj = new B(); obj.foo(); // Компилятор рассматривает obj как A, в котором нет throws, и не знает о том, что он бросает checked-исключение
Вы можете бросить unchecked-исключение, на основе RuntimeException или Error, без добавления throws в сигнатуру перезагруженного метода. Конечно, если вам не нужно именно checked-исключение.

Допустимо ли использовать yield return внутри блокировки?

Есть два вопроса к коду, приведенному ниже:
Допустимо ли использовать yield return внутри блокировки? Что произойдёт с блокировкой, когда мы будет крутить метод Get() в цикле foreach?
public IEnumerable Get() { _lock.EnterReadLock(); try { foreach (var item in _dictionary) { yield return new SomeObject(item.Key, item.Value); } } finally { _lock.ExitReadLock(); } }
private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();


Ответ

Смотрите, это возможно на уровне языка — компилятор не имеет возможности проверить. Но делать так не рекомендуется.
Общее правило такое: следует избегать вызова чужого кода под блокировкой. Допустим, вы нарушили правило и выполнили yield под блокировкой. Клиентский код может при этом сделать вызов в другой поток (если у нас нету многопоточности, то блокировки нам всё равно не нужны, правильно?).
foreach (SomeObject o in Get()) { Dispatcher.Invoke(() => Process(o)); }
Если в методе Process будет браться та же блокировка, у вас будет взаимная блокировка, и код зависнет: Process будет дожидаться отпускания блокировки, а блокирующий код — возвращения из yield (то есть, следующей итерации цикла).

Анимация желе с SVG

Есть такой элемент SVG

В браузере выглядит так: ссылка
Это часть из этой картинки:
Как сделать непрерывную желеобразную анимацию? Может посоветуете какую-нибудь библиотеку? Такая подойдет? — ссылка


Ответ

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

Почему скрипт на Питоне не понимает юникод?

Скрипт #! /usr/bin/env python print "Привет" выдает ошибку File "./y.sh", line 2 SyntaxError: Non-ASCII character 'xd0' in file ./y.sh on line 2, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details Что нужно добавить, чтобы сказать интерпретатору о наличии юникода?


Ответ

Нужно добавить в начало специальный комментарий. #! /usr/bin/env python # -*- coding: utf-8 -*-
print "Привет"

Как определить степень схожести двух текстов?

Допустим, взяли исходный текст, три абзаца. В его копии убрали полностью последнее предложение, поменяли адрес ссылки где-то в тексте, заменили пару предлогов, и заменили пару слов на синонимы. Каков алгоритм, чтобы определить "эти тексты сходны на 65%. Скорее всего, общий первоисточник"? Есть ли что-то вроде вэйвлет анализа для текстов?


Ответ

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

Как сохранить копию проекта в Git'е?

Вот такая ситуация, работаю с Git.
В проекте имплементировал несколько классов которые обрабатывают нотификацию.
Теперь оказалось, что это не нужно. Но я много времени провел над этим и хотел бы оставить себе копию того, что сейчас получилось...
Как можно сохраниться, вырезать все что не нужно, но потом если нужно чтоб можно было вернуться обратно?


Ответ

если внесённые вами изменения останутся в общем хранилище (т.е., история не будет переписана ради удаления ваших изменений), то просто запомните хэш последнего вашего коммита, чтобы позже можно было к нему вернуться:
на «бумажке»; создав указатель на этот коммит (очень «лекговесная» операция — в хранилище будет создан всего один файл размером 41 байт):
либо фиксированный — метку (tag):
$ git tag имя.метки коммит
кстати, пока вы явно не укажете отправить ваши метки в общее хранилище (например, с помощью опций --tags или --all команды push), ваши коллеги и не узнают о их существовании: они будут храниться только в вашей локальной копии хранилища; либо «плавающий» — ветку (branch):
$ git branch имя.ветки коммит
аналогично, пока вы явно не отправите этот указатель в общее хранилище (например, с помощью опции --all команды push, или конкретно упомянув указатель — git push общее.хранилище имя.ветки), ваши коллеги также не узнают о существовании этого указателя. если внесённые вами изменения ещё не отправлены в общее хранилище или будут принудительно удалены из него (методом переписывания истории), вы можете создать ещё одну копию хранилища:
с рабочим каталогом (т.е. со всеми файлами, история которых отслеживается):
$ git clone /путь/к/текущему/хранилищу /путь/к/копии или без рабочего каталога (для экономии места):
$ git clone /путь/к/текущему/хранилищу /путь/к/копии --bare или даже «пакет» (bundle):
$ git bundle create файл.с.пакетом набор.коммитов

а уж как впоследствии можно будет воспользоваться сохранённым указателем или копией хранилища — «тянет» на другой, не менее многословный ответ.

Что будет если подключившись к серверу по SSH закрыть терминал без команды exit?

Что будет если подключившись к серверу по SSH закрыть терминал без команды exit?


Ответ

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

скрипт для проверки:
#!/bin/bash
trap 'touch hupped; exit' hup
echo $$
while :; do sleep 1; echo -n .; done
сначала он выводит номер своего процесса, а затем раз в секунду выдаёт в stdout символ «точка». при получении сигнала hup создаёт в текущем каталоге файл hupped и завершает работу.

Расшифровать инфу из байтов

У меня есть 100 байт. Вот они:
65 5A 44 5B 58 44 43 8A 4B 5A 4A 5B 41 4F 58 8A 42 4D 8A 40 4A 46 47 55 84 8A 68 8A 47 4F 45 5A 42 58 55 4D 4A 58 4F 41 56 47 51 5F 8A 40 8A 46 44 4E 4F 8A 45 44 5B 4F 41 4F 47 42 55 5F 8A 46 44 4C 4F 58 8A 5B 41 59 4C 42 58 56 8A 48 8A 40 4A 5D 4F 5B 58 48 4F 8A 59 40 5A 4A 52 4F 47 42 55 84 A7 A0
Теперь они и у вас есть. В них написан какой-то осмысленный текст. Предположительно русский (выдернуто из игры). Байты как я понял перевернуты. Что это за кодировка такая, что там написано и, чёрт возьми, кто тот герой, что сможет объяснить как их правильно конвертнуть в этом случае?


Ответ

Браслет из камня. В непритязательных к моде поселениях может служить в качестве украшения.
Вы были абсолютно правы, текст, явно из игры :)
Шифр элементарный. С каждый байтом строки в кодировке windows (1251) произведен XOR с 0xAA
Догадаться было не сложно, по частоте символов мы определили, что чаще всего встречается 8A, предположили, что это пробел. Далее я обратил внимание, что это практически единственный байт, который больше 0x80, остальные байты гораздо меньше. А как известно, у пробела самый маленький код 0x20, латинские символы начинаются с 0x41, а русские так вообще во второй половине таблицы, после 0x80. Получается все крупные числа превратились в мелкие, а маленькое число наоборот в большое - это явный признак операции XOR, тем более она обычно и используется в криптографии т.к. легко обратима, повторением операции. 0x8A xor 0x20 = 0xAA - вот наш ключ. Сделал маленькую прогу, которая считала ваши шестнадцеричиные коды символов, сделала из них числа и провела xor 0xAA. Текст перед нами.
На perl моя программа выглядела так:
#!/usr/bin/perl $a=<>; // Читаем строку из входного файла @b=split(/ /,$a); // Делаем массив hex кодов, они через проблел foreach $a (@b) // бежим по массиву { $n=hex($a) ^ 0xAA; // Делаем нормальное число из шестнадцетиричного и XOR 0xAA print(chr($n)); // Печатаем символ с этим кодом }

Ненужные файлы в папке Release/Debug C# WinForms

Написал небольшое приложение. Хочу его внедрить для одного из научных порталов. Компилировал проект, выходящей папкой которого была Release. Сейчас структура папки такова:
database.txt,options,log.xlsx - файлы/директория, используемые программой ну и spamer.exe- исполняемый файл само собой.
Скажите, пожалуйста, с остальными файлами что? Они жизненно важны для работы программы? Как почистить папку по максимуму? Т.к. инсталлятор делаться не будет, а конечным вариантом программы должна быть папка с filename.exe внутри (эдакая portable версия)


Ответ

foo.application — манифест для установки приложений ClickOnce. Если вы им пользуетесь, то оставьте, собственно. foo.exe.config — конфигурационный файл, содержащий глобальные настройки. Может содержать настройки версии .NET, строки для подключения к базе, настройки логирования и т. п. Часто можно удалить без последствий, но не рекомендуется. foo.exe.manifest — манифест, содержащий совместимость с версиями ОС и оболочки, необходимый уровень прав и т. п. Обычно подходят настройки по умолчанию, но удалять не рекомендуется. foo.pdb — файл для отладки. При возникновении исключений обеспечивает подробную информацию о стеке вызовов. Можно оставить, чтобы ошибки от клиента было проще анализировать. foo.vshost.* — файлы для хитрого запуска приложения при отладке в Visual Studio. Можно спокойно удалять.

Различаются ли строки не более чем на один символ?

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


Ответ

Алгоритм для случая, когда длины строк заранее не известны и в общем случае вообще не доступны, т.е. это потоки байт или файлы целиком не умещающиеся в памяти.
int teststr(char *s1,char *s2) { int k0=1,k1=1,k2=1; while(*s1==*s2 && *s1) {s1++; s2++;} // Ищем первое несовпадение char o1,o2; if(!*s1 && !*s2) return 1; // Строки равны do { o1=*s1++; o2=*s2++; k0=k0 && c1==c2; k1=k1 && c1==o2; k2=k2 && c2==o1; if(!(k0 | k1 | k2)) return 0; // Обнаружена ошибка (строки не преобразуемы) } while(o1 && o2); if( (!o1 && *s2) || (!o2 && *s1) ) return 0; // Расхождение длин строк более чем на 1 return 2; // Строки преобразуемы за одно действие }
Работает за один прямой проход строки до конца (если строки равны) или до первой обнаруженной ошибки. Т.е. максимальная сложность O(n).
Сначала идет сканирование строк до первого несовпадения. После этого начинается цикл идущий от точки несовпадения. Он сравнивает текущие символы двух строк, они равны в случае если предыдущее расхождение было заменой символа. А так же текущий символ одной строки с предыдущим символом другой строки, они равны в случаях если один символ был вставлен или удален и следовательно произошел сдвиг одной из строк. Одно из этих равенств должно сохранятся от точки когда было встречено первое расхождение и до конца строк.
Для любителей UTF-8 привожу полный код, нормально разбирающий данную кодировку с символами разной длины. Замечу, что он поймет любые символы, включая китайские иероглифы и т.п. Если нужна кодировка с символами фиксированной длины, большей чем байт, т.е. например UTF-16, то это решается проще, заменой char на short в предыдущем коде.
#include unsigned int utf32(char **s) { unsigned char b=(unsigned char)**s; unsigned int code=0; int n=-1; if(b) (*s)++; if(! (b & 0x80) ) return b; b<<=1; while(b & 0x80) {b<<=1; n+=5; code=code<<6|**s & 0x3F; (*s)++;} code|= b << n; return code; } int teststr(char *s1,char *s2) { int k0=1,k1=1,k2=1; unsigned int c1,c2,o1,o2; do {c1=utf32(&s1); c2=utf32(&s2);} while(c1==c2 && c1); if(!c1 && !c2) return 1; do { o1=c1; o2=c2; c1=utf32(&s1); c2=utf32(&s2); k0=k0 && c1==c2; k1=k1 && c1==o2; k2=k2 && c2==o1; if(!(k0 | k1 | k2)) return 0; } while(o1 && o2); if( (!o1 && c2) || (!o2 && c1) ) return 0; return 1; } int main() { char *s1="Тестюabc"; char *s2="ТестЦюabc"; if(teststr(s1,s2)) printf("True
"); else printf("False
"); }

Можно ли как-нибудь упростить инициализацию классов на Python?

У меня есть конструктор класса примерно вот такого вида:
class A: def __init__(self, a1, a2, ..., an): self.a1 = a1 self.a2 = a2 ... self.an = an ...
Можно ли как-то упростить процесс инициализации, а то писать n повторяющихся строчек совсем не интересно.
UPD. Дополню вопрос: 1) Как быть в случае, когда присутствуют значения по умолчанию?
class B: def __init__(self, b1=b1_0, b2=b2_0, ..., bn=bn_0): self.b1 = b1 self.b2 = b2 ... self.bn = bn ...
2) Возможно ответ последует из п.1, но всё равно задам ещё один вопрос: Что делать, если для каких-то аргументов есть значение по умолчанию, а для каких-то нет?


Ответ

Если неизменяемый объект хотите создать, представляющий запись с полями, можно использовать collections.namedtuple
from collections import namedtuple
A = namedtuple("A", "a1 a2 an") A.__new__.__defaults__ = (0,) * 3 # set default values print(A(1, 2)) # -> A(a1=1, a2=2, an=0)
Для изменяемых объектов, можно использовать types.SimpleNamespace:
from types import SimpleNamespace
print(SimpleNamespace(a1=1, a2=2, an=3)) # -> namespace(a1=1, a2=2, an=3)
SimpleNamespace это простая альтернатива конструкции: class NS: pass, которая за вас __init__, __repr__, __eq__ методы определяет.
Чтобы указать типы, в неизменяемом случае, можно использовать typing.NamedTuple
from typing import NamedTuple
class B(NamedTuple): b1: str = '0' b2: int = 1
print(B()) # -> B(b1='0', b2=1) print(B(b2=3)) # -> B(b1='0', b2=3)
PEP 557 -- Data Classes (Python 3.7+) хочет ввести классы данных для случая «изменяемые namedtuple со значениями по умолчанию». Для предыдущих версий Питона, можно использовать неинтегрированную в стандартную библиотеку реализацию из dataclasses пакета
from dataclasses import dataclass # $ pip install dataclasses
@dataclass class B: b1: str = '0' b2: int = 1
print(B()) # -> B(b1='0',b2=1) b = B(b2=2) print(b) # -> B(b1='0',b2=2) b.b1 = '1' print(b) # -> B(b1='1',b2=2)
В более общем случае, можно воспользоваться attrs пакетом, который множество дополнительной функциональности предоставляет. См. ещё примеры в ответе на похожий вопрос: Как создать коллекцию объектов пользовательского класса?

Текущая директория в Python

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


Ответ

Если вы запускаете скрипт C:\Scripts\script.py из D:\work папки:
D:\work> py C:\Scripts\script.py
то:
D:\work — это текущая рабочая директория на момент старта скрипта. open('file.txt') будет пытаться открыть D:\work\file.txt файл C:\Scripts — это директория со скриптом.
Текущая рабочая директория
Текущая рабочая директория возвращается os.getcwd() функцией, где CWD это Current Working Directory ("текущая рабочая директория"). os.getcwdb() возвращает путь в виде байт. Происхождение функции от POSIX getcwd(3). Другие способы могут вернуть разные результаты в зависимости от настроек доступа промежуточных директорий, общей длины (от платформы зависит) итд—не изобретайте своих способов, если не осознаёте всех последствий возможного изменения в поведении функции. Также нетрадиционные способы получения рабочей директории могут ухудшить читаемость другими Питон-программистами. Из The Zen of Python
There should be one-- and preferably only one --obvious way to do it.
По умолчанию относительные пути используют именно эту директорию, поэтому явно вызывать os.getcwd() редко нужно. Например, open('file.txt') вызов открывает файл 'file.txt' в текущей директории. Если необходимо передать полный путь в виде строки, то можно использовать os.path.abspath('file.txt')—getcwd() снова явно не используется.
Path.cwd() из pathlib модуля возвращает путь к текущей директории как объект c разными полезными и удобными методами такими как .glob('**/*.py')
Директория со скриптом
Текущая рабочая директория может отличаться от директории с текущим Питон-скриптом. Часто, но не всегда можно os.path.dirname(os.path.abspath(__file__)) использовать, чтобы получить директорию с текущим Питон скриптом, но это не всегда работает. Посмотрите на get_script_dir() функцию, которая поддерживает более общий случай
Если хочется получить данные из файла, расположенного относительно установленного Питон-модуля, то используйте pkgutil.get_data() или setuptools' pkg_resources.resource_string() вместо построения путей c помощью __file__. Это работает даже, если ваш пакет упакован в архив. В Python 3.7 появился importlib.resources модуль. К примеру, если у вас есть Питон пакет data внутри которого лежит файл.txt, то чтобы достать текст:
import importlib.resources
text = importlib.resources.read_text('data', 'файл.txt')
Если вы хотите найти место куда пользовательские данные можно положить, то appdirs модуль предоставляет переносимый способ:
import appdirs # $ pip install appdirs
user_data_dir = appdirs.user_data_dir("Название приложения", "Кто создал")
Разные платформы (Windows, MacOS, Linux) используют разные соглашения, appdirs позволяет не плодить сущностей и использовать на каждой платформе подходящие директории.

Зачем мы реализовываем IEquatable, если Equals() есть в Object?

Разбирая тему обобщений (по Шиелду 4.0), потребовалось написать обобщённый метод, который вернет логическое значение true, если в массиве содержится некоторое значение. Далее в книге поясняется, что так как T - обобщённый тип, то для сравнения объектов обобщённого типа необходимо что бы класс этих объектов реализовывал интерфейс IEquatable с параметром T или IEquatable. Написано так же, что в данных интерфейсах определен метод для сравнения Equals(). Отсюда сразу же несколько вопросов:
Во-первых, почему для сравнения объектов обобщённого типа нам вообще необходимо реализовывать какие-либо интерфейсы? Метод Equals() относится к методам определённым в Object => есть в каждом объекте. Я понял что для сравнения объектов в данном примере нужно реализовать описанные выше интерфейсы, но я не понял, ПОЧЕМУ это нужно сделать.
Во-вторых, по Шиелду, как я написал выше, для сравнения объектов в обобщённом методе предлагается реализовать Equtable с параметром T или IEqutable. Один параметризирован, другой нет. Вопрос - какой в каком случае необходимо использовать?
Далее Шиелд в своей книге демонстрирует пример метода, который проверяет, находится ли в массиве некоторое значение. Вот этот метод:
public static bool IsIn(T what, T[] obs) where T : IEquatable { foreach(T v in obs) { if (v.Equals(what)) { return true; } else { return false; } } }
Тут так же есть два вопроса.
Во-первых, начну с того, что данный метод не работает. Студия выдает ошибку компиляции "Не все ветви метода возвращают значение". Я несколько раз перепроверял написанный код, но ошибка остается. Как это исправить?
Во-вторых, я не уверен, правильно ли я понял, что сигнатура данного метода подразумевает, что в данный метод могут быть переданы только объекты тех типов, которые реализовывают интерфейс IEquatable? Другими словами, если я захочу передать в метод массив каких нибудь студентов, и найти в нём Васю Пупкина, то мой класс студента должен выглядить следующим образом?
class Student : IEquatable { public string Name; public string Surname;
public bool Equals(T other) { //some code for compare return false; } }
Прошу последовательно ответить на все вопросы. Спасибо


Ответ

Equals(object obj) появился в .NET в самом начале, а тогда еще не было дженериков. До введения дженериков в .NET 2.0, переопределение метода Equals(object obj) в большинстве случаев выглядело приблизительно так:
public bool override Equals(object obj) { if (obj == null) return false; if (obj is MyClass) { MyClass other = (MyClass)obj; // сравниваем this и other } return false; }
Получается, в большинстве случаев, объекты разных типов не могут быть равны. Что бы упростить жизнь, придумали интерфейс IEquatable, в котором можно сразу сравнивать 2 объекта, без проверок их типов (что тоже занимает некоторое время).
По-хорошему теперь вы должны реализовать IEquatable для всех классов, которые можно сравнивать. При этом вы должны не забывать про переопределение старого Equals, для совместимости. Можно делать например вот так:
public bool override Equals(object obj) { return Equals(obj as MyClass); }
public bool Equals(MyClass other) { if (other== null) return false; // сравниваем объекты }

Почему буквы алфавита с “р” по “ю” не входят в диапазон “а-я”?

Поясню сразу: я знаю, что python 2 требует явного объявления строк как юникодовых. Понимаю, что это и не должно работать корректно. Мне интересна "анатомия" поломки. Что именно внутри re.compile() и regex.search() производит такой результат?

Судя по нижеприведённому коду, диапазон 'а-яё' не включает в себя диапазон 'р-ю', зато диапазон 'р-ю' включает 'ё'.
mcve.py:
# coding=utf-8
import re
# Это панграмма, она содержит все буквы алфавита test = 'широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства'
regex1 = re.compile('[а-яА-ЯёЁ\s]+') regex2 = re.compile('[а-яА-ЯёЁшьрэтфцюыхущчъ\s]+') regex3 = re.compile('[а-яёшьрэтфцюыхущчъс\s]+') regex4 = re.compile('[а-яр-ю\s]+')
print regex1.search(test).group() print regex2.search(test).group() print regex3.search(test).group() print regex4.search(test).group()
Результат:
� широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства
Я убедился, что все буквы алфавита от "А" до "Я" и от "а" до "я" идут в Юникоде подряд, кроме "Ёё", которые явным образом добавлены в регулярное выражение.
Постепенно добавляя буквы, на которых прерывается поиск по первому выражению, я пришёл к диапазону а-яА-ЯёЁшьрэтфцюыхущчъ. Если отсортировать добавленные буквы, получается почти сплошной интервал: "ртуфхцчшщъыьэю"
Если убрать заглавные буквы, т.е. "[А-ЯЁ]", то неожиданным образом поиск прерывается на "с". Интервал становится сплошным: с "р" и до "ю". Это regex3
И наконец оказывается, что теперь интервал можно свернуть и даже убрать "ё" (regex4).
Что вообще происходит?
python --version Python 2.7.6

Если явным образом сделать юникодовую строку и регулярное выражение, то всё работает как должно. Но ведь как-то работает и без этого. Объясните, как?
test2 = u'широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства' regex5 = re.compile(u'[а-яА-ЯёЁ\s]+')


Ответ

Самый простой способ посмотреть, что же не так с регуляркой - поставить debug флаг. Причем в таком случае абсолютно нет нужды лезть в потроха - они покажут то же самое. В этом можно убедиться, если залезть руками в %python_folder%/Lib/sre_parse.py и добавить там пару print-ов на строку 438 - выглядит она как-то тактак:
elif this == "[": # character set set = [] setappend = set.append ## if sourcematch(":"): ## pass # handle character classes if sourcematch("^"): setappend((NEGATE, None)) # check remaining characters start = set[:] while 1: this = sourceget() if len(this) == 1: # Вот ровно в этом месте парсер перебирает содержимое [] print(source.tell(), "ORD: ", ord(this)) if this == "]" and set != start: break
Так вот этот print покажет все абсолютно то же самое, что и debug - то что буковки на самом деле не буковки.
regex1 = re.compile('[а-яА-ЯёЁ\s]+', re.DEBUG)
max_repeat 1 2147483647 in literal 208 range (176, 209) literal 143 literal 208 range (144, 208) literal 175 literal 209 literal 145 literal 208 literal 129 category category_space
Сразу видно, что что-то совсем нечисто, потому что первым должен быть range(ord('a')-ord('я'), а вместо него чепуха какая-то. А все от того, что строки в кодировке UTF8 (указана явно в файле), а тип у них - байты. Они могут отображаться нормально в терминале, если кодировки совпадают. Я пользуюсь Pycharm и его консоль в UTF8. Но если бы я запустил то же самое на стандартном терминале винды, то отобразилась бы натурально каша (типа такой - ╨Я╤А╨╕╨▓╨╡╤В), ибо кодировка CP866.
Например,
print("Привет") # НО! for char in "Привет": print(ord(char), repr(char))
В debug выводе число 208 - это первая половинка UTF8 символа 'а' - 176 - вторая половинка, затем следует дефис и снова первая половинка символа 'я' - в этом можно убедиться, открыв исходник в любом HEX редакторе. В итоге неверный интервал. Соответственно, когда парсер перебирает содержимое квадратных скобок он натыкается не на буквы, а на байты, а точнее на половинки букв в кодировке UTF8. Можно симулировать поведение регулярки таким кодом:
reg_min = 144 reg_max = 209
result = [] for char in test: ordedr = ord(char) if ordedr >= reg_min and ordedr <= reg_max: result.append(char) else: break print(ord(regex1.search(test).group())) print(list(map(ord, result)))
>>> 209 >>> [209]

Сравнение двух списков на нахождение элементов которые соответствуют правилам

Вопрос заключается в том, что например у меня есть два списка:
lst1 = ['1', '2' , '3' , '4'] lst2 = ['123', '234' , '345' , '334']
Как мне найти такие элементы во втором списке, которые включают в себя только те элементы, которые есть в первом, но, если в первом списке есть одна единица, то например элемент "112" с второго списка не подходит.
Tо есть результатом программы должен быть
ls3 = ['123', '234']
'345' - не подошло потому что там есть элемент "5" которого нет в первом списке
'334' - не подошло потому что там есть два элемента "3", а в первом списке элемент "3" есть только один


Ответ

Если известно как определить, можно ли составить строку word из заданных символов chars, используя каждый символ в chars не более его числа повторений (известен can_build(word, chars) предикат), то задача сводится к:
result = list(filter(can_build, lst2))
или более читаемо:
result = [word for word in lst2 if can_build(word)]
где can_build использует chars = lst1 внутри.
Если бы требовалось использовать все символы из chars, тогда это была бы проверка является ли word анаграммой chars, к примеру: "просветитель" можно получить перестановкой букв "терпеливость". Можно использовать похожие решения, когда точное равенство заменено на "не более".
can_build() можно реализовать, найдя является ли word мультимножество подмножеством chars мультимножества. Если бы все символы в chars и word были уникальны, то
can_build = set("1234").issuperset
collections.Counter реализует идею множества, в котором элементы могут повторяться, то есть мультимножества. Как показано в элегантном решении в ответе @Timofey Bondarev, эту коллекцию можно использовать чтобы реализовать can_build
can_build = lambda word, chars=Counter(lst1): not (Counter(word) - chars)
Можно реализовать тот же алгоритм вручную, не используя collections.Counter.
from collections import defaultdict
def Counter(letters): counts = defaultdict(int) for letter in letters: counts[letter] += 1 return counts
chars_count = Counter(chars)
def can_build(word): return all(chars_count[char] >= count for char, count in Counter(word).items())
Можно использовать простой список, если все символы принадлежат какому-либо алфавиту, тогда так как chars всё время один и тот же, то можно закэшировать chars.count значения. Например, если chars может содержать только цифры 0-9
from string import digits
chars_count = [(digit, chars.count(digit)) for digit in digits]
def can_build(word): return all(word.count(digit) <= count for digit, count in chars_count)
это O(N * M) решение (M=len(digits)—размер алфавита), в отличии от O(N) решения, использующего Counter(). Если алфавит нефиксированный: alphabet = set(word), тогда это O(N**2) (квадратичный) алгоритм. Если alphabet фиксированный как в примере, то это O(N) (линейное) решение. Для небольшого алфавита, например, для boolean цифр (alphabet=(0,1)) или ДНК-строк (alphabet="GTAC"), это решение могло быть даже быстрее решения с Counter()
Ещё пример применения: если word, chars это числа, представленные их простыми множителями (например: (2,2,3) представляет 12, (5,7) представляет 35), тогда can_build() отвечает на вопрос является ли word делителем chars, то есть верно ли что: chars % word == 0
Q: как реализовать код, если избавиться от условия о том, что элемент должен повторяться столько раз сколько его есть в первом списке???
Уже ответ в этом предположении работает. Иначе это был бы случай с анаграммами: количество повторений совпадает. Решения с Counter() и с <=, >= НЕ требуют, чтобы элемент повторялся "столько раз сколько его есть в первом списке" (можно меньше).
Если вы имеете ввиду, что количество повторений вообще не важно, а интересует только есть элемент или нет, то ситуация аналогична случаю когда все элементы уникальны, то есть:
can_build = set(lst1).issuperset
как уже упомянуто выше.

Ssh соединение постоянно рвётся после 5 минут простоя

Подключаюсь к своему серверу по ssh -> иду в гугл искать команду, например, для поиска файла -> возвращаюсь, а окно git bash не отвечает -> перезапускаю его -> ввожу заново пароль.
Это крайне раздражает. Почему так и что с этим делать?


Ответ

Обычно sshd сервер закрывает неактивные соединения. Часто сталкилвался, что маршрутизаторы также рвут соединения, которые "молчат".
Можно уговорить клиента всё время посылать я-живой сигнал. В ~/.ssh/config надо добавить (в секундах):
Host * ServerAliveInterval 120
Если файла ешё нет, надо создать и во избежание ошибки
Bad owner or permissions on ~/.ssh/config
не забыть изменить права на запись (в некоторых версиях также и на чтение):
chmod go-rw ~/.ssh/config # или chmod 600 ~/.ssh/config
Без конфигурации можно попробовать: ssh -o ServerAliveInterval=120 iam@my.home.ru
Подробнее man 5 ssh_config
В PuTTY это устанавливается в меню - Connection>Seconds between keepalives (0 to turn off).

Как устроены ключи шифрования Telegram?

Вопрос по устройству протокола telegram и ключей шифрования.
Спецслужбы просят у телеграмма ключи и настаивают, что это требование не идёт вразрез Конституции РФ: мы не спрашиваем сообщения пользователей, мы просим только ключи.
Тогда пардон что это за такие бесполезные ключи вообще? Ими ничего нельзя расшифровать? И вообще, как устроены эти ключи: на каждого пользователя телеграм хранится ключ и ФСБ требует шесть ключей по уголовным делам о терроризме? Или они хотят некий золотой ключ, которым можно будет расшифровать любое сообщение всех ста миллионов пользователей телеграмма?
Ссылки по теме:
Тинькоф журнал. Телеграм не смог оспорить приказ ФСБ в суде. Что это значит


Ответ

Cогласно общим часто задаваемым вопросам можно кое-что узнать о ключах для хранящейся на серверах информации
Секретные чаты там не хранятся вовсе. О ключах и речи не идёт. Для несекретных чатов они утверждают, что распределяют ключи по нескольким юрисдикциям, чтобы для раскрытия какой-либо информации потребовались распоряжения судов из нескольких сразу. Чтобы такое произошло, должно произойти нечто экстраординарное.
Согласно часто задаваемым вопросам для технарей (technically inclined) можно сделать некоторые выводы о возможностях расшифровки передаваемого трафика
Из-за того, что при передаче повсюду используются ключи, согласованные по протоколу Диффи-Хеллмана (ДХ), если сервер Telegram не сохраняет сессионных ключей (что он теоретически может, но вряд ли делает), то расшифровка ранее записанных данных скорее всего невозможна, т. к. и сервер и клиент могли уже давно забыть к ним ключ. У Телеграма есть приватный RSA-ключ для проверки подлинности сервера, публичный "брат" которого зашит в клиенты. При наличии этого приватного ключа возможно устроить MITM-атаку, заставив клиентов в подконтрольной сети считать собственный сервер подлинным сервером Telegram, из-за чего клиенты будут считать канал доверенным и приступят к согласованию сессионных ключей с самозванцем, который в свою очередь сможет от лица клиента связаться с настоящим сервером. У Телеграма есть сессионные ДХ-ключи для общения с конкретными клиентами (а от одного аккаунта может подключиться несколько клиентов) об облачных чатах (где нет оконечного шифрования). Их нет смысла сохранять, когда можно в любой момент договориться о новом, поэтому, вероятнее всего, хоть этот ключ и существует, его нет смысла раскрывать, т. к. действителен он будет недолго. Для секретных чатов ДХ-ключи генерируются для защиты взаимодействия не с сервером, а непосредственно с адресатом. Так что серверы ни на каком этапе не получают готового ключа и не могут их выработать даже имея записанный трафик процедуры согласования ключа. Потому что это Диффи-Хеллман
Поскольку Telegram трубит о максимальной приватности, есть основания полагать, что сессионных ключей они не сохраняют. Исходя из всего этого, ФСБ могут интерсовать два вида ключей, т. к. это единственные ключи с достаточным временем жизни, чтобы их имело смысл получать заранее:
Приватный RSA-ключ сервера — да, им нельзя ничего расшифровать, но с его помощью можно получить сессионный ключ у настоящего сервера Telegram и расшифровать данные, которые можно с его помощью запросить: якобы клиентом у настоящего сервера. Т. е. выполнить MITM-атаку Ключи шифрования (неизвестного типа) данных на жёстких дисках серверов для облачных чатов (секретные существуют в расшифрованном виде лишь на клиентских устройствах), если вдруг удастся заполучить данные с дисков из серверов Telegram. Сколько их и какова область каждого ключа, из-за закрытости серверного кода Telegram достоверно не известно, клиенты с этими ключами никак не работают; теоретически там может и не быть шифрования. Эти ключи имеют хоть какой-то смысл при наличии, скажем, дисков из серверов. И даже в этом случае может подложить свинью полнодисковое шифрование.

Разумеется, я предполагаю, что протокол Диффи-Хеллманна и RSA достаточно криптостойки в тех местах, на которые в них рассчитывают. Если их всё же проломят, устойчивость Telegram будет меньшей из проблем, которые в результате этого всплывут. На этих протоколах основывается львиная доля взаимодействий в интернете — HTTPS, например.

Swift - что за зверь? [закрыт]

Несколько минут назад apple представило новый яп - swift. Говорят про него они так: он objective-c without c.
Предлагаю писать сюда всё, что известно о нём. Ну там он динамичный/статичный и т.п.
P.s. Objective-C


Ответ

На первый взгляд, очень похоже на C#, статически типизированный объектно-ориентированный язык. Вот список того, что есть в C# и появилось в Swift по сравнению с Objective C. Автоматический вывод типов переменных. Лямбды с нормальным синтаксисом, гораздо удобнее, чем блоки. Memory safety и отсутствие wild pointer'ов в качестве бонуса. Дженерики. Циклы наподобие foreach value types и reference types, структуры и классы Функции — объекты первого класса (раз уж есть лямбды...) type safety, отсутствие undefined behaviour Nullable Именованные аргументы функций, out-параметры (отречёмся от старого ми-и-ира!) string interpolation (будет в C# 6) поддержка safe-навигации (будет в C# 6) Теперь преимущества: Есть let — объявление констант внутри тела функции. В C# есть такое лишь в ограниченном контексте (LINQ query syntax). Неясна точная семантика: это deep const или shallow const? Если deep, имеет ли объект право измениться сам по себе? Синтаксическая поддержка инициализации списков, словарей и кортежей. Расширения (extensions) сильнее, чем Extension Methods из C#: добавляются статические методы, а также имплементируются протоколы. (Не знаю, как это соотносится с категориями Objective C.) Delegation — очень похоже на mix-in'ы, хочу такое в C#. Мощнейший switch с pattern matching'ом. Вложенные функции! (Надеюсь, они наследуют контекст.) where-constraint в generic'ах мощнее Конструктор базового класса можно вызывать где угодно, не только в начале. AOP-образные willSet и didSet Укороченный синтаксис для лямбд ($1 etc.) Отличия, забавные и серьёзные: Garbage collector'а нету, есть ARC. Ручная расстановка слабых ссылок и проблемы с closure в комплекте. Миленькие trailing closures. Методы по умолчанию виртуальные, как в Java. Массивы и словари — value type, копируются при передаче в качестве параметров. Более правильный порядок записи типов: тип после переменной, тип возвращаемого значения после аргументов Приятная конструкция if let для safe navigation. Чего не увидел: Нет LINQ-образных lazy enumerations event'ы? Без них программирование UI не очень удобно. А где исключения? Опять пробрасывать nil? Встроенная в язык поддержка многопоточности? Пора бы уже, 2014 год.

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

Добрый день!
Мне нужно объединить два массива строкового типа, каким простым способом я могу сделать это?
String[] bothArray(String[] first, String[] second) { return ??; }


Ответ

Если разрешено использовать 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); }
Компактно, красиво и не требует внешних компонентов.

Ограничить возможности стороннего класса C#

Имеется (модульное) игровое приложение - арена, в нем реализован абстрактный класс (или интерфейс) для игрока. Игроков (игровые ИИ) наследуют от указанного класса и разрабатывают сторонние разработчики и предоставляют в виде скомпилированного dll. Есть ли вообще возможность ограничить возможности этой сторонней dll? Ну, например защититься от "FORMAT C:" или от пересылки данных по сети, чтения с диска и т. д. Пусть даже этот класс падает в этом случае - тогда игроку просто засчитывается техническое поражение.
Какой день бьюсь, но, хоть убейте, никак не пойму, как заставить это работать. Как сделать чтобы все сторонние игроки работали в песочнице? Сейчас есть примерно такой код:
static class PlayersHost { static public List Players;
static public void LoadPlayers() { Players = new List();
var files = Directory.EnumerateFiles(Path.Combine(Environment.CurrentDirectory, "Players"), "*.dll"); foreach (var file in files) { try { var asm = Assembly.LoadFrom(file); var types = asm.GetTypes(); foreach (var type in types) { try { IPlayer player = (IPlayer)Activator.CreateInstance(type); players.Add(player); } catch { } } } catch { } } } }
Потом я просто при старте приложения загружаю всех игроков:
PlayersHost.LoadPlayers();
и пользуюсь полученной коллекцией, например:
var player = PlayersHost.Players[0]; try { player.PrepareToPlay(); } catch { }
Нужно решение с использованием AppDomain


Ответ

Для изолирования частично доверенного кода в .NET предусмотрен механизм ограничения доступа в рамках AppDomain - это называется Sandbox (запуск в песочнице).
AppDomain.CreateDomain( string friendlyName, Evidence securityInfo, AppDomainSetup info, PermissionSet grantSet, params StrongName[] fullTrustAssemblies);
Информация о том, как его использовать, а также ряд дополнительных соображений и нюансов подробно описаны в этой статье на MSDN: https://msdn.microsoft.com/ru-ru/library/bb763046(v=vs.110).aspx

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

Приводится на хабре в статье библиотека Apache Commons Logging (не знаю смысл этой библиотеки, не юзал) и комментарий:
За System.out.println для вывода логов начинающим программистам уже через неделю обучения следует отрубать руки.
Так вот вопрос: а почему print настолько плох?
P.S. Сам я основы языка очень плохо знаю.


Ответ

Логирование - это все-таки больше, чем вывод строк в консоль. Здесь имеют место следующие параметры:
Цель: это может быть консоль (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 совершенно точно по умолчанию пытается добавить сообщение пять раз на тот случай, если что-то пошло не так).

Как сделать волнистую полоску на css?

Подскажите, как можно сделать вот такую полоску лесенкой с помощью css


Ответ

На html и css
*{ box-sizing:border-box; } body{ margin:0; } .angles{ display:flex; align-items:flex-start; list-style:none; padding:0 0 0 10px; } .angles li{ width:30px; height:30px; border:4px solid yellow; border-left:none; border-bottom:none; transform:rotate(-37deg) skewX(14deg); transform-origin:center; margin-right:14px; }


На svg
#angles{ stroke-width:3px; stroke:yellow; fill:none; }

Что значит инкапсулировать?

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


Ответ

В разработке ПО есть два схожих понятия – инкапсуляция и сокрытия информации. Кто-то считает, что это синонимы, кто-то нет, но это не так и важно.
Немного истории: Дэвид Парнас в году эдак 70-м в статье “On the Criteria To Be Used in Decomposing Systems into Modules” впервые ввел понятие сокрытия информации, как ключевого инструмента проектирования. Звучал этот принцип примерно так: декомпозиция системы на модули не должна основываться на анализе блок схем или потоков исполнения. Вместо этого, каждый модуль должен прятать внутри некоторое решение (design decision), предоставляя минимальное количество информации о нем своим клиентам.
Вот небольшой пример.
Допустим, вы разрабатываете ынтырпрайз приложение, которое делает что-то важное. Любое нормальное приложение обычно требует некоторой конфигурации: ну, параметры подключения к БД или серверу, и другую ценную информацию. И вот, матерый артихектор (*) вместе с не менее матерым клиентом просят прочитать конфигурацию из конфигурационного файла.
(*) это не опечатка, пожалуйста, не правьте это!
В процессе разговора с ними вы понимаете, что никто толком не знает, почему читать конфигурацию нужно именно из файла, какой должен быть у него формат и что именно там должно храниться.
Теперь вы становитесь перед выбором: вы можете «размазать» сведения о конфигурации ровным слоем по всему приложению. Каждый компонент, которому нужны некоторые параметры, сам полезет в app config, вытянет оттуда нужные данные, пропарсит xml или json и будет готов служить. С другой стороны, очевидно, что решение о том, где именно хранится конфигурация и в каком формате, может измениться в будущем. Поэтому более вменяемым решением будет скрыть информацию о местоположении и формате конфигурации в одном модуле, например, с помощью классов Configuration и ConfigurationProvider. В этом случае, когда (да, именно, «когда», а не «если») требования изменятся, то поменяется лишь реализация класса ConfigurationProvider, а все остальные пользователи этого класса или конфигурации останутся неизменными. Аналогично, при изменении формата, поменяется тоже только процесс парсинга, а не потребители конфигурации.
Этот пример кажется надуманным, но это не так! Мы довольно часто сталкиваемся с изменчивостью требований, но используем, к сожалению, один из двух подходов:
• Полностью игнорируем возможность изменения требований и делаем все в лоб или
• Создаем супер сложное решение с десятком уровней косвенности, которое должно выдержать изменения требований в любом направлении без изменения кода вообще.
Более же разумный подход находится где-то по середине. Каждый раз, когда я начинаю разработку некоторой фичи, я думаю, сколько кусков в коде придется поменять, если требования или детали реализации существенно изменятся. При этом я не стараюсь свести количество изменений к 1 (ну, типа, если мы следуем SRP, то должно быть только одно место, в случае изменения требованй). Я стараюсь, чтобы этих мест было мало, а изменения были простыми.
Собственно, это и есть суть information hiding и его младшей сестры – инкапсуляции.

Модификатор strictfp

Для чего нужен данный модификатор? И с чем его можно использовать?


Ответ

strictfp - это модификатор, введенный в java 1.2, ограничивающий точность вычислений с float и double по стандарту IEEE. Для чего это нужно? Чтобы обеспечить переносимость. Дело в том, что JVM использует всю возможную точность процессора, а она на разных системах разная, поэтому и результат может получиться разный.Данный модификатор используется в программах требующих точность вычислений превышающих IEEE (обычно, что-нибудь связное с наукой).
strictfp class StrictFPClass { double num1 = 10e+102; double num2 = 6e+08; double calculate() { return num1 + num2; } }

strictfp interface StrictFPInterface { double calculate(); strictfp double compute(); // compile error }

class StrictFPMethod { strictfp double computeTotal(double x, double y) { return x + y; } }

В классе он обозначает, что все методы будут на всех системах возвращать вещественные числа с одинаковой точностью. 0.112 и 0.113 Если эти числа сравнивать с точность до сотых, то они будут одинаковы. Пример, как точность влияет на вычисления. Его можно не использовать т.к. почти все компиляторы современные уже его за нас подставляют (где-то читал такое в мануале) Дополнил.

_tmain() почему такое название?

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


Ответ

Всё просто.
Для не-Unicode-программ используется соответствующее стандарту имя main и список параметров int argc, char* argv[]
Для Unicode-программ список параметров в MSVC выглядит как int argc, wchar_t* argv[], и во избежание конфликтов с исходниками и компиляторами, соответствующими стандарту, функция называется wmain
Для программ, которые могут компилироваться и в Unicode-, и в не-Unicode-режиме, список аргументов выглядит как int argc, _TCHAR* argv[], где макрос _TCHAR определён как char или wchar_t в зависимости от значения макроса _UNICODE. Таким образом, нужно третье имя для функции. Так и было придумано имя _tmain
Всё это, конечно, требует некоторой магии компоновщика, который должен уметь определить entry point не только в функции main, как по стандарту, а и в функциях wmain/_tmain
Если вы уверены, что вам не нужно Unicode-приложение, вы можете переименовать функцию в main и дать ей список аргументов int argc, char* argv[], чтобы соответствовать стандарту. Или если вы твёрдо решили, что ваша программа будет запускаться лишь под линейкой WinNT/XP/7 (а не Win95/98), вы можете остановиться на Unicode-варианте и переименовать функцию в wmain (соответственно, аргументы должны быть int argc, wchar_t* argv[]).

Запоздалое уточнение (спасибо @alexolut): Согласно документации, _tmain определяется в при помощи typedef как main или wmain, так что в вашей программе всё равно будет либо main, либо wmain
(И да, вы можете опустить параметры, или добавить третий параметр envp, или задекларировать возвращаемый тип void.)

Округление дробных чисел до целых

Какие существуют в Java стандартные средства для округления чисел?
Пример округления: 3.49 - 3, 3.50 - 4, 3.51 - 4.


Ответ

Math.ceil(n) — возвращает наименьшее целое число, которое больше или равно аргумента n. Math.floor(n) — возвращает наибольшее целое число, которое меньше или равно аргументу n. Math.round(n) — возвращает целое число, ближайшее к аргументу n (округляет n).
Пример с ceil
int result = (int)Math.ceil(3.8); System.out.println(result); //4
int result = (int)Math.ceil(3.3); System.out.println(result); //4
Пример с floor
int result = (int)Math.floor(3.8); System.out.println(result); //3
int result = (int)Math.floor(3.3); System.out.println(result); //3
Пример с round
int result = (int)Math.round(3.8); System.out.println(result); //4
int result = (int)Math.round(3.3); System.out.println(result); //3

Зачем нужен паттерн “итератор”?

На курсах C# регулярно говорят о паттерне "итератор". Зачем он вообще нужен если мы можем нужные элементы отправить в коллекцию и работать уже с ней? Зачем нужны пользовательские коллекции если можно использовать стандартные?


Ответ

Итератор это "не пользовательские коллекции", а инструмент обхода этой коллекции и не только коллекции, а вообще всего, что можно последовательно перебрать по какому то алгоритму. Обход коллекции всего лишь частный случай.
Алгоритм перебора скрыт внутри итератора, что позволяет иметь отдельно сам объект данных и много итераторов с разными алгоритмами обхода (SRP)
То есть итератор - класс инкапсулирующий в себе какой алгоритм обхода данных со стандартизированным интерфейсом "перечислитель"

Что означает const*?

Именно со звездой - демонические конструкции могут принимать вид
const char* const* blah_blah,
char const* blah
int const* const integer,
int* const* const и так далее в самых разных комбинациях. Как расшифровать сии начертания и зачем вообще может кому-то понадобиться оборачиваться в const, будто шелкопряду?


Ответ

Такие записи проще всего рассматривать справа налево. Например,
Данное объявление
const char * const * blah_blah;
объявляет указатель с именем blah_blah, который указывает на константный указатель (так как квалификатор const предшествует *, если смотреть справа налево), который указывает на константный объект типа char.
Вот пример простой программы, который облегчает понимание этого объявления.
#include
int main(void) { const char * const * blah_blah; const char *p = "Hello"; blah_blah = &p; puts( *blah_blah ); }
На консоль будет выведено
Hello
Можно ввести typedef имена для наглядности
typedef const char CONST_CHAR_TYPE; typedef CONST_CHAR_TYPE *POINTER_TO_CONST_CHAR_TYPE;
const POINTER_TO_CONST_CHAR_TYPE *blah_blah;
в этом случае переменная blah_blah является указателем на константный указатель на константный объект типа char
Я думаю будет легче понять эти объявления, если следовать грамматике определения указателя.
Указатель в стандарте C определяется следующим образом
pointer: * type-qualifier-listopt * type-qualifier-listopt pointer
то есть за знаком * может следовать список квалификации, который к нему относится.
Поэтому предыдущее объявление можно записать как
const char ( * const ( *blah_blah ) );
Можно сделать и сам указатель blah_blah константным. Но тогда он должен быть явно инициализирован при объявлении, если имеет автоматическую продолжительность памяти. Например
const char ( * const ( * const blah_blah ) ) = /* некоторое значение */;
или
const char * const * const blah_blah = /* некоторое значение */;
Вот демонстрационная программа, в которой сам указатель blah_blah также объявлен как константный.
#include
int main(void) { const char *p = "Hello"; const char ( * const ( * const blah_blah ) ) = &p; puts( *blah_blah ); }
Объявление этого указателя читается как константный указатель на константный указатель на константный объект типа char
В объявления функций, имеющих прототип, можно опускать идентификатор параметра.
Ниже представлена такая программа
#include
void display( const char ( * const ( * const ) ) ); void display( const char * const * const ); void display( const char ( * const ( * ) ) ); void display( const char * const * );
int main(void) { const char *p = "Hello"; display( &p ); }
void display( const char * const * const blah_blah ) { puts( *blah_blah ); }
Так как объявлений одной и той же функции (без ее определения) может быть несколько, то все выше указанные функции объявляют одну и ту же функцию. Так называемый квалификатор верхнего уровня, который относится непосредственно к параметру, можно убрать из объявления функции. То есть (еще один пример) эти пары функций объявляют одни и те же функции
void f( const int x ); void f( int x );
и
void g( int * const p ); void g( int * p );

Зачем typedef объвлять с одним и тем же типом

Наверно какие-то C-шные ухищрения. Навроде их классов. Вроде бы и объявление тут уже есть. Может поэтому? Вот такая строка например (из OpenCV):
typedef struct CvFileStorage CvFileStorage;
Зачем же так писать? Не нашел никак, сходу, ответ на это. Когда-то (несколько лет назад), помню что читал об этом. Тогда чистый C был в моде наверное, а сейчас такое позабыто получается. Еще подобное видел в коде от Windows CE6 и др. Это запомнил:), а для чего нужно не помню никак. Если еще какие-то доп. куски кода надо привести, то скажите. Эта строка стоит перед структурой, которая у себя где-то в поле использует тип из этого typedef-а. Но зачем так писать, а не просто объявить его? Спасибо.


Ответ

Имеется по крайней мере две веские причины объявить этот typedef.
typedef struct CvFileStorage CvFileStorage;
Первая причина заключается в том, что в C программах вы должны указывать ключевые слова struct или enum перед именем структуры или перечисления. Это выглядит обременительно при вводе кода. Очень часто программисты забывают указать эти слова, что приводит к появлению ошибки компиляции. Поэтому этот typedef упрощает жизнь программистам, позволяя им не писать эти ключевые слова перед именем структуры или перечисления.
Вторая причина состоит в том, что имена структур и другие идентификаторы находятся в различных пространствах имен. Поэтому одно и то же имя можно использовать для объявления структуры и обычной переменной. Например, следующий фрагмент кода является корректным
struct CvFileStorage { //... };
int CvFileStorage;
В этом фрагменте кода объявляется структура с именем CvFileStorage и переменная типа int с тем же самым именем. Эти объявления не конфликтует друг с другом, так как, как уже было написано, перед именем структуры обязательно должно следовать ключевое слово struct .
В C вы можете записать, к примеру
struct CvFileStorage { int CvFileStorage; } CvFileStorage;
Это объявление корректно, так как эти три совпадающих идентификаторs находятся в различных пространствах имен.
Однако это может вводить в заблуждение читающих код, так как если программист по ошибке опустит ключевое слово struct перед именем структуры, то может оказаться, что код по-прежнему с точки зрения синтаксиса языка будет корректным, хотя на самом деле имелась в виду структура, а не переменная с таким же именем.
Например, в данном выражении программист по невнимательности забыл указать ключевое слово struct, и тем не менее получил корректное выражение, так как имеется переменная с таким же именем
sizeof( CvFileStorage )
Чтобы избежать такой путаницы также целесообразно резервировать это имя без ключевого слова struct для имени структуры, используя typedef..
В С++ ключевое слово struct можно опускать при обращении к структуре. Тогда возникает вопрос: а как быть с тем, что в C можно объявлять переменную или функцию с таким же имеенем как имя структуры?
Этот вопрос решается следующим образом: имя переменной или имя функции скрывает объявление структуры с тем же самым именем. Поэтому при обращении к структуре надо указывать уточненное имя.
Например,
struct CvFileStorage { //... };
void CvFileStorage();
В этом фрагменте кода объявление функции скрывает объявление одноименной структуры. Поэтому если, например, вы хотите объявить объект этой структуры, то надо будет указывать уточненное имя структуры.
struct CvFileStorage obj;
Или, например, можно написать такие объявления
struct CvFileStorage { //... };
void CvFileStorage( struct CvFileStorage );
Эти имена не будут конфликтовать друг с другом, так как для структуры используется ее уточненное имя.

Почему нужно инкапсулировать то, что изменяется?

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


Ответ

Инкапсулировать то, что изменяется, нужно потому что это экономит время и силы на изменения того, что зависит от того, что может быть изменено.
Практический пример
Исходя из того, что под инкапсуляцией изменяемого обычно понимается абстрагирование в смысле скрытия конкретного принципа действия, можно предложить следующий пример.
Вы проектируете объект банковского счета, который сейчас работает с одной базой данных. Если представить что объект счета может работать с совершенной другой базой данных (или даже с текстовыми файлами), то, если вы сразу заложитесь на это при проектировании интерфейса этого объекта, вам не придётся переписывать код, который задействует объект счета.
protected function save() { // сохраним в файл file_put_contents('account.txt', json_encode($this)); }
public function add($amount, $explanation) { $this->balance += $amount; $this->account[] = [$amount, $explanation]; $this->save(); }
public function withdraw($amount, $explanation) { $this->balance -= $amount; $this->account[] = [-$amount, $explanation]; $this->save(); }
/* Пропустим другие методы */ }
Если для изменения баланса счета вызывается метод, в числе параметров содержащий только сумму и обоснование, то пользователю объекта будет совершенно не нужно знать, к какой именно базе данных обращается объект счета чтобы сохранить изменения.
Например, этой функции нет никакой разницы от того, использует ли переданный её счет какую-то базу данных или файлы - вся разница в работе счета инкапсулирована
add($this->totalCharge, $this->getExplanation()); }
/* Пропустим другие методы */ }
Функция addToAccount будет одинаково хорошо работать как с экземпляром класса Account, так и с экземпляром класса DatabaseAccount
account as list ($amount, $explanation)) { $this->database->updateRec($amount, $explanation); } }
/* Пропустим другие методы */ }
Благодаря правильно спроектированному интерфейсу класса Account вы сможете как угодно менять принципы сохранения данных внутри Account без необходимости менять что-то в классах, использующих класс счета.
Зачем ещё это может быть нужно?
Кроме удобства для последующего изменения стоит учитывать и фактор когнитивной нагрузки на программиста. И абстрагирование, и сокрытие информации позволяют её снизить. Например, для использования того же объекта счета программисту не нужно думать ни о БД, ни об ручной обработке исключительных ситуаций. Инкапсуляция делает несущественными конкретные детали, которые программисту не нужно изменять, в идеальном случае полностью избавляя от необходимости думать о них.

Как хранятся в памяти литералы?

Как хранятся в памяти литералы?
int main() { 5; 1.; ""; }


Ответ

С абстрактной точки зрения "в памяти" в языке С++ хранятся только lvalues. Из приведенных вами литералов только строковый литерал "" является lvalue, т.е. только он хранится в памяти.
Остальные литералы не являются lvalue и формально положения в памяти не имеют.

Фактически же целочисленные литералы обычно "встраиваются" в тот контекст, в котором они использованы. Они могут встроиться непосредственно в сгенерированную машинную команду (то есть стать частью кода, а не данных программы), а могут вообще неузнаваемо трансформироваться или бесследно раствориться в этом контексте: умножение на 8 может замениться на сдвиг влево на 3 разряда, а присваивание переменной значения 0 может замениться на машинную инструкцию обнуления.
Что произойдет с литералом с плавающей точкой — зависит от способностей компилятора и особенностей подлежащей машинной платформы. На платформе x86 в общем случае плавающий литерал действительно будет храниться в памяти, т.е. для его хранения будет заведена внутренняя переменная. В то же время компилятор вправе распознавать "особенные" плавающие константы (0.0, 1.0 и т.д.) и реализовывать их неявным образом. Но, еще раз, в любом случае на уровне языка плавающий литерал положения в памяти не имеет.

В чем разница между Func<> и delegate?

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


Ответ

Ну, есть ключевое слово delegate — это описание сигнатуры функции, т. е., её списка параметров и типа возвращаемого значения. Используется так:
public delegate bool MyPredicate(int x);
Им можно пользоваться так:
private bool IsOdd(int i) { return i % 2 != 0; }
private Analyze(MyPredicate p, int x) { bool result = p(x); if (result) Console.WriteLine("found!"); }
Analyze(IsOdd, 1); // печатает "found!"
С другой стороны, есть готовые, предопределённые сигнатуры функций (Func с возвращаемым значением, Action без). То есть, можно не определять делегат самому, а воспользоваться готовыми Func и Action. Аналогичный пример:
private bool IsOdd(int i) { return i % 2 != 0; }
private Analyze(Func p, int x) { bool result = p(x); if (result) Console.WriteLine("found!"); }
Analyze(IsOdd, 1); // печатает "found!"
Если для вашей сигнатуры подходит Func или Action, особого смысла определять свой делегат нету. Или есть, если вы хотите дать своему делегату более подходящее имя, чем просто Func, и хотите подчеркнуть его семантику
Существуют случаи, когда свой делегат всё же необходимо объявлять. Например, наличие out- и ref-параметров:
public delegate Updater(ref int x); // невозможно выразить через Func

Для полноты, вот (надеюсь, полный) список вариантов, когда вам придётся объявлять делегат:
Когда список аргументов чересчур длинный (для .NET 4+ более 16 аргументов, для .NET 3.5 больше 4 аргументов) Когда ваши аргументы содержат ref, out или params Если ваш делегат рекурсивен (например delegate D D(D d)). Как ни странно, такие штуки иногда нужны

Можно ли обойтись без статического конструктора?

Мне понятно, что статический конструктор служит для присвоения значений статическим переменным, что он вызывается в первую очередь при создании объекта класса.
Но зачем он нужен, если я могу присвоить эти значения при объявлении переменных?


Ответ

В языке C# существует несколько способов инициализации полей:
В месте объявления В конструкторе
Вот наивный пример:
class Foo { private string s1 = "s1"; private string s2;
private static string s3 = "s3"; private static string s4;
public Foo() { s2 = "s2"; }
static Foo() { s4 = "s4"; } }
Если смотреть с высоты птичьего полета, то инициализация по месту реализуется довольно просто: выражение, использованое для инициализации поля переносится в соответствующий конструктор - в экземплярный конструктор для экземплярны полей и в статический конструктор для статических полей.
Тут нужно сказать, почему у нас два конструктора. Конструктор экземпляра - это некоторая вспомогательная функция, призванная инициализировать экземпляр создаваемого объекта. Например, мы можем сказать, что любой валидный объект должен обладать некоторым поведением (инвариантом) и конструктор - это специальная функция, обязанная его обеспечить. Инвариантом может быть что угодно: начиная от того, что некоторое поле не нулевое, заканчивая более сложными правилами, например, что сумма полей дебет и кредит равна 0.
Помимо инвариантов объектов существуют еще и инварианты типа: т.е. некоторые условия, которые должны быть верными не для конкретных объектов, но для типа целиком. Поведение типа выражается с помощью статических членов, а значит "инвариант" типа - это валидное состояние статичесих переменных, ответственность за валидность которых обеспечивает статический конструктор.
В отличие от конструктора объекта конструктор типа не вызывается пользователем. Вместо этого, он вызывается CLR в момент первого обращения к типу (опустим точные правила).
Существует тонкие различия в поведении во время исполнения, которое отличает использование инициализатора полей в месте объявления от инициализации этих же полей в конструкторе. Инициализаторы статических и экземплярных полей - это синтаксический сахар, но очень важно знать, какой именно!
Разница в случае экземплярных полей и конструкторов
Все инициализаторы экземплярных полей перемещаются компилятором C# в экземплярных конструктор. Но главный вопрос здесь: куда именно.
В общих чертах конструктор экземпляра выглядит следующим образом:
// ctor // Код инициализаторов полей // Вызов конструктора базового класса // Код текущего конструктора
У данного алгоритма есть два важных следствия. Во-первых, код инициализаторов экземплярных полей не просто помещается в конструктор, он помещается в самое его начало, еще до вызова конструктора базового класса, и во-вторых, он будет скопирован во все экезмплярные конструкторы
Первое замечание очень важно (да, об этом могут спросить на собеседовании и это может пригодиться в реальных приложениях). Например, если кто-то вздумает вызвать виртуальный метод в конструкторе базового класса, то часть полей будет проинициализированы, а часть нет. Несложно догадаться, что поля, проинициализированные в месте объявления уже будут валидными, а другие поля будут содержать дефолтные значения.
Да, да, да, вызывать виртуальные методы в конструкторах базового класса - это плохо, но в реальность такое бывает и нужно понимать, что в этом случае будет в рантайме.
Разница в случае статических полей и конструкторов
Со статическими конструкторами дела обстоят несколько сложнее и проще одновременно. С точки зрения наследования, способ инициализации статических полей никак не пересекается с вызовом статического конструктора базового класса. Никак. Там вообще процесс вызова статических конструкторов отличается от экземплярных. Например, при создании экземпляра наследника вначале вызывается статический конструктор наследника, а потом статический конструктор базового класса. А если дергается статический метод наследника, то статический конструктор базового класса вообще не вызовется автоматом (вызовется только если статический метод наследника как-то дернет базовый тип).
Но сложность возникает с тем, когда именно будет вызван статический конструктор.
Как уже написал @Qwertiy наличие или отсутствие статического конструктора в классе влияет на то, когда будет вызван этот самый конструктор. Наличие статического конструктора приводит к генерации странного специального флага, который затем скажет CLR, что можно более вольно относиться к времени вызова статического конструктора, и сделать это теперь можно будет не прямо перед первым обращением, а, например, перед вызовом метода, в котором это обращение происходит.
Потенциально, это может повлиять на эффективность приложения, поскольку теперь проверка будет делаться один раз, а не тысячи раз, при условии, что первое обращение находится в цикле от 0 до 1000.
Заключение
Инциализатор полей (статических и нет) - это сахар, но он может быть с горчинкой, если не понимать, к чему приводит его чрезмерное использование.
Обычно я пользуюсь следующим эмпирическим правилом. Для экземплярных полей: нужно инициализировать поле аргументом конструктора - (без вариантов) использую конструктор; в противном случае - инициазатор полей. В случае статических полей: в подавляющем числе случаев использую инициализатор. Если кода много, то выделяю метод.
Если мне нужно использовать статический конструктор, чтобы задать порядок инициализации или изменить семантику инициализации типа, то я добавляю огромный комментарий, который говорит, почему к этому фрагменту кода нужно относитсья очень внимательно.
Если мне нужно использовать инициализатор для экземплярных полей, чтобы инициализация прошла до вызова конструктора базового класса, то я рефакторю код, чтобы этого было не нужно. Например, выделяю фабриный метод. Если же такоей поведение действительно нужно, то тут нужен двухстраничный комментарий, который объясняет почему это нужно и почему другие варианты не подходят.

Последовательности чисел Фибоначчи

Подскажите по коду, правильный ли он или что можно доделать и дописать. Как можно организовать это с циклом while?
Задача:
Выведите на экран первые 11 членов последовательности Фибоначчи. Напоминаем, что первый и второй члены последовательности равны единицам, а каждый следующий — сумме двух предыдущих.
public class Test { public static void main(String [] args){ int a = 1; int b = 1; int n; int sum_fib; Scanner s = new Scanner(System.in); n = s.nextInt(); for(int i = 0; i < n; i++){ sum_fib = a + b; a = b; b = sum_fib; System.out.print(sum_fib + " "); } } }


Ответ

Я бы написал просто
System.out.print("1 1 2 3 5 8 13 21 34 55 89");
А в вашем коде все нормально. По-моему, единственный способ плохо написать вычисление последовательности Фибоначчи - это
int fib(int i) { if (i == 1) return 1; if (i == 2) return 1; return fib(i - 1) + fib(i - 2); }
то есть способ с использованием рекурсии.

В чем проявляется “ссылочность” строк в C#

Строки в C# - ссылочный тип. Но следующий код
string s1 = "string 1"; string s2 = s1; s2 = "string 2"; Console.Write(s1);
выведет string 1. В чем же проявляется "ссылочность" строк в C#?


Ответ

Всё в порядке.
string s1 = "string 1"; string s2 = s1; bool b = string.ReferenceEquals(s1, s2); // -> true s2 = "string 2"; bool b2 = string.ReferenceEquals(s1, s2); // -> false
Т.е. до того, как вы написали s2 = "string 2", s1 и s2 ссылались на один и тот же объект, но как только вы это написали, был создан новый объект и s2 стала ссылаться на него, а s1 так и осталась ссылаться на первый объект.

Справится ли C# с управлением другой программы

Справится ли C# с управлением другой программы? Насколько он хуже или лучше чем C++ в этом плане? Справится ли с этой задачей VB.NET?
Требуется.
Изменить размеры окна стороннего приложения. Отправить приложение на самый нижний Z уровень, чтобы оно не появлялось поверх других открытых окон, в то время когда на нем будут происходить какие то действия, например нажатия кнопок. Требуется выбирать в выпадающем списке нужный пункт и далее нажимать кнопку для применения настроек.
Понимаю что это все можно сделать через WinApi но не понимаю где взять описания функций (желательно на русском) и как их встраивать в код C#. Например, как это делалось в VB 6.0 помню.


Ответ

c# справится. Справится любой язык умеющий вызывать winapi Хуже только тем, что нужно объявить функции winapi и возможно структуры у vb те же возможности, что и у c#
Вам сюда http://www.pinvoke.net/ за тем как объявлять функции winapi в c# и vb.net
Возможно подойдет что-то более высокоуровневое вроде Cruciatus от 2GIS

В каких случаях возникает потребность использования raw pointers в современном C++?

После появления новых возможностей в C++ таких как std::make_shared() и std::make_unique то возникает вопрос : А есть ли хоть один случай, когда действительно нужно работать с сырым указателем?
В этом вопросе я не учитываю случаи, когда стороняя библиотека в каком-либо из методов принимает указатель.
Я беру среднего по уровню программиста на C++. Он пишет свою библиотеку без использования сторонего кода. И у меня не находится ни одного примера, когда ему действительно нужно пользоваться сырыми указателями.


Ответ

Во внутренних деталях реализации, когда владеющие указатели усложняют взаимодействие, когда нужно разделять владение, но время жизни объекта чётко детерминировано и не возникает вопроса: где и когда чистить объект (shared_ptr в таких случаях - лишнее), когда ссылкой не обойтись, потому как возможна ситуация с nullptr у объекта. В публичных API стараться избегать, пока это возможно, либо чётко обосновывать - "почему?" и "зачем?".
В общем, я придерживаюсь правила: обходиться без сырых указателей, пока это возможно. Пока не подводило (embedded).
Кстати, возможно забавно, но в C проектах, при достижении определённого уровня сложности, тоже начинают появляются механизмы разделяемого владения. Это всем известные xxx_ref(object)/xxx_unref(object). Примеры: GLib со своим gobject, FFmpeg активно внедряет подсчёт ссылок для AVPacket и AVFrame (для таких случаев в Boost существует intrusive_ptr), ядро Linux тоже не стоит в стороне (https://lwn.net/Articles/336224/ по слову Reference Counting или http://www.makelinux.net/books/lkd2/ch17lev1sec7) со своим kobject

Хранение 10^30 записей в БД

Мне нужно как то сохранить 1 (30 нолей) записей, и осуществить поиск в них за примерно 20 секунд. Записи вида (ключ > значение) Каким образом это дело осуществить то? Я понимаю одной базой тут не обойтись? =) p.s. записей: 1 000 000 000 000 000 000 000 000 000 000


Ответ

Ваше число записывается как 10^30;
Терабайт - Это 10^12. Петабайт - 10^15. Эксабайт - 10^18.
Рассмотрим стандартный телекомовский шкаф высотой 42U. В него можно поместить, при двухсторонней упаковке, 42 дисковые полки высотой 2U
Предположим, что на одной полке стоит 24 диска по 4 Тб, итого, один шкаф хранит 42*24*4= 4032 Тб данных, или 4 Пб.
Вам потребуется всего лишь 10^(30-15)/4=10^15/4 шкафов. Полагая, что шкаф занимает 1 квадратный метр, делаем вывод, что вам понадобится 10^15/4 квадратных метра. Это 10^9 / 4 квадратных километра.
Площадь суши составляет 5*10^8 квадратных километра.
Потребуется еще 1.5 планеты.

Грамотное использование try-catch

Вычитал, что использование try-catch весьма ресурсоёмко. Так ли это?
Если так, то как следует грамотно использовать try-catch?
Теоретически ведь можно практически всё делать по старинке, через коды возврата, минуя использование try-catch, но тогда код пострадает в плане читаемости из-за громоздких последовательностей if или switch.


Ответ

Для начала определите для себя, что такое «ресурсоёмко». Любой вопрос производительности стоит рассматривать в контексте с производительностью всей остальной программы. Если у вас алгоритм на целочисленной арифметике, то в нём try/catch может заметно замедлять производительность (а может и не замедлять). Если у вас идёт запись в файлы или обращение к базе данных, то обработка исключения будет на порядки быстрее остальных операций, поэтому нет никакого смысла её оптимизировать.
Обычно try/catch нисколько не замедляет программу, если исключений фактически нет. То есть кидая исключение только в случае ошибки, вы не потеряете в производительности, когда ошибок нет. Если же ошибка произошла, то работа вашего алгоритма всё равно будет прервана, поэтому не так важно, что вы один раз потеряете дополнительно пару микросекунд (вряд ли больше) перед выдачей ошибки пользователю.
Вам стоит беспокоиться, только если вы в цикле кидаете миллион исключений, потом их ловите, игнорируете и переходите на следующую итерацию. Но такой код как раз уже попахивает: получается, вы используете исключения для управления потоком вычислений, а не для информирования об исключительной ситуации. Но даже в такой ситуации JIT-компилятор может сообразить. Если в пределах заинлайненного кода он увидит и выбрасывание исключения и поимку и заметит, что при поимке вы игнорируете исключение (в частности, не читаете стектрейс из него), то он потенциально может заменить выбрасывание исключения на обычный goto, не создавая объект исключения вообще. Вообще обычно самое медленное в исключении — это создание стектрейса.
Общее правило: пишите код так, как рекомендуют авторы языка и признанные специалисты в данной области. Если производительность кода вас не устраивает, профилируйте его, находите узкие места и оптимизируйте именно их (возможно, отступая от красоты кода в угоду скорости). Но не оптимизируйте то, что занимает полпроцента от общего времени выполнения. Не надо оптимизировать преждевременно.

Сокрытие использования PHP

В статье "PHP: фрактал плохого дизайна" на хабре, открыл ссылку и на открывшейся странице открыл еще одну ссылку PHP Credits
Далее попробовал аналогичное (?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000) на знакомых сайтах, отобразилось, но не на всех, что значит, есть решение.
Немного погуглив, ответ нашелся, в настройках php.ini установить expose_php = Off
Топик не является вопросом, а может информация кому пригодится.
Еще по теме


Ответ

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

Поиск прямоугольника на изображении

Задача: Найти жёсткий диск на фото, определить его угол и контуры
Проблема: Не всегда удаётся найти правильный контур диска.
В коде я делаю изображения серыми, блюрю, нахожу разницу между ними и определяю контуры, но решение не точное. Хотелось бы вашей помощи.
firstFrame = cv2.imread(bg_im) # Фоновое изображение без диска frame_img = cv2.imread(frame) # Изображение с диском
gray = cv2.cvtColor(frame_img, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (21, 21), 0) firstFrame = cv2.cvtColor(firstFrame, cv2.COLOR_BGR2GRAY) firstFrame = cv2.GaussianBlur(firstFrame, (21, 21), 0)
frameDelta = cv2.absdiff(firstFrame, gray) thresh = cv2.threshold(frameDelta, 25, 255, cv2.THRESH_BINARY)[1] thresh = cv2.dilate(thresh, None, iterations=2) (cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
rect = cv2.minAreaRect(c) box = cv2.cv.BoxPoints(rect)
x1 = box[0][0] x2 = box[1][0] x4 = box[3][0]
y1 = box[0][1] y2 = box[1][1] y4 = box[3][1]
perimeter_1_4 = sqrt((x4 - x1)**2 + (y1 - y4)**2) perimeter_1_2 = sqrt((x2 - x1)**2 + (y1 - y2)**2)
box = np.int0(box) corner = list(rect)[2]
if perimeter_1_4 > perimeter_1_2: corner = -(90 - corner)
cv2.drawContours(frame_img,[box],0,(0,0,255),2)


Ответ

Как только речь заходит о применении размытия с большим размером ядра, то, к сожалению, получается необратимая деформация объекта интереса. Объект контурами вроде и выделен, но при этом по своим размерам, форме (а подчас и положению) может иметь значительное расхождение с оригиналом. Стоит ли говорить, что морфологические операции (эрозия, дилатация), наложенные поверх, лишь усугубляют проблему.
В ситуации с представленными изображениями сложность возникает ещё и от того, что лента конвейера имеет весьма различимые следы производственного пользования. Это царапины, пятна и прочие элементы подобного рода, которые на фоновом изображении и изображении с объектом интереса имеют разное положение, да и вообще в деталях различаются значительно. Этот момент становится принципиальным, когда производится попиксельное вычитание одного изображения из другого.
В целом задача сводится к тому, чтобы не повредив сам объект, попытаться выделить его на общем фоне. Попробуем пойти от обратного и вместо того, чтобы применять размытие повысим резкость краёв.
void subtractPyr(const cv::Mat &src_mat, cv::Mat &dst_mat, int iterations) { std::vector sizes(iterations);
cv::Mat mat = src_mat.clone(); for(int i = 0; i < iterations; ++i) { sizes[iterations-(i+1)] = mat.size(); cv::pyrDown(mat, mat); }
for(int i = 0; i < iterations; ++i) cv::pyrUp(mat, mat, sizes.at(i));
cv::subtract(mat, src_mat, dst_mat); }
cv::Mat src1_mat = cv::imread("foreground.jpg"); cv::Mat src2_mat = cv::imread("background.jpg");
cv::Mat gry1_mat, gry2_mat; cv::cvtColor(src1_mat, gry1_mat, cv::COLOR_BGR2GRAY); cv::cvtColor(src2_mat, gry2_mat, cv::COLOR_BGR2GRAY);
subtractPyr(gry1_mat, gry1_mat, 5); subtractPyr(gry2_mat, gry2_mat, 5);
Изображение с объектом интереса:

Фоновое изображение:

Несмотря на то, что фоновое изображение имеет свой набор шумов, тем не менее оно содержит и те детали, которые полезно вычесть из изображения с объектом интереса. После этого можно выполнить бинаризацию.
cv::Mat gry_mat = gry1_mat - gry2_mat;
cv::Mat bin_mat; cv::threshold(gry_mat, bin_mat, 1, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
Получим следующую маску:

Здесь хорошо заметна одна из проблем, связанная с неверно подобранным освещением. Левый верхний угол объекта интереса частично растворён, что не позволяет произвести поиск контура, опоясывающего объект, с корректным результатом.
Так или иначе продолжим именно через поиск контуров и отсеивание их по площади с эмпирически подобранным размером. Их иерархия больше не потребуется, а значит объединим все точки в один единственный большой контур.
std::vector > contours; cv::findContours(bin_mat.clone(), contours , cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
std::vector big_contour;
for(auto itr = contours.begin(); itr != contours.end(); ++itr) { if(cv::contourArea(*itr) > 300.) { const std::vector &contour = *itr; for(auto itr2 = contour.begin(); itr2 != contour.end(); ++itr2) { big_contour.push_back(*itr2); } } }
Если нарисовать большой контур, то можно увидеть, что лишние детали на изображении более не захватываются, а сам он в целом лежит внутри границ объекта интереса.

Остаётся получить опоясывающий объект интереса прямоугольник.
cv::RotatedRect rc = cv::minAreaRect(big_contour);
cv::Point2f points[4]; rc.points(points);
// Нарисуем его. for(int i = 0; i < 4; ++i) cv::line(dst_mat, points[i], points[(i+1)%4], cv::Scalar(0,0,255));
Как хорошо видно на следующем изображении полученный прямоугольник совершенно не идеально описывает объект интереса. Эта проблема связана с оптической деформацией этого самого объекта, а также с наличием довольно широкой тени, присутствующей с левой его стороны. К сожалению, эти проблемы нельзя устранить иначе, кроме как подстройкой объектива камеры и освещения.