Страницы

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

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

Как проигнорировать фигурные скобки в функции string.Format

Как проигнорировать фигурные скобки в функции string.Format? Пример:
string.Format("{Name:{0}}", "Value");
В результате выполнения данного кода мы получим исключение
An unhandled exception of type 'System.FormatException' occurred in mscorlib.dll Additional information: Input string was not in a correct format.
Что нужно сделать, для того, чтобы избавится от ошибки и получить в результате строку:
{Name:Value}


Ответ

Открытие и закрытие скобок интерпретируется как начальный и конечный элемент для функции форматирования строки. Для того чтобы вывести фигурную скобку в строке нужно ее продублировать {{ для открытия скобки и }} для ее закрытия. Исправленный вариант будет выглядеть следущим образом:
string.Format("{{Name:{0}}}", "Value");
Детали можно посмотреть на MSDN, а также тут

Как передать все значения item в RecycleView?

У меня есть recycleview с данными и мне надо передать все данные items в другое активити,как мне это реализовать?


Ответ

Зачем делать такой костыль как в предыдущем ответе, если любую модель можно сделать сериализуемой (implements Parcelable) и передавать всю модель целиком?
Кладем в intent: intent.putExtra("parcelable", myParcelables.get(position))
Берем из intent: MyParcelable model = getIntent().getParcelableExtra("parcelable")
пример реализации:
public class Country implements Parcelable {
private String code;
private String name;
private String tag;
private int limit;
private String image;
public Country(JSONParser data) { code = data.getString("code"); name = data.getString("value"); tag = data.getString("flag"); image = data.getString("image"); if (data.contains("limit")) { limit = data.getInt("limit") - code.length(); } }
public Country(Parcel in) { code = in.readString(); name = in.readString(); tag = in.readString(); image = in.readString(); limit = in.readInt(); }
public static final Creator CREATOR = new Creator() { @Override public Country createFromParcel(Parcel in) { return new Country(in); }
@Override public Country[] newArray(int size) { return new Country[size]; } };
@Override public int describeContents() { return 0; }
@Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(code); dest.writeString(name); dest.writeString(tag); dest.writeString(image); dest.writeInt(limit); }
public String getClearCode() { return code; }
public String getCode() { return "+" + code; }
public String getName() { return name; }
public String getTag() { return tag; }
public int getLimit() { return limit; }
public String getImage() { return image; } }
P.S.
Чтобы не словить BadParcelableException при передаче между активностями Parcelable-конструктор должен инициализировать данные в том же порядке, в котором они были записаны в Parcel в методе void writeToParcel(Parcel, int)

Не находит std::begin, std::end

Пишу простую шаблонную функцию in_array. По замыслу, она должна работать с любыми типами. Вот код:
template bool in_array(T needle, const T* haystack) { T *e = std::find(std::begin(haystack), std::end(haystack), needle); if (e != std::end(haystack)) return true; else return false; }
Получаю ошибки:
std::begin: не найдена соответствующая перегруженная функция
То же для std::end. В чем моя ошибка?


Ответ

Для указателей стандартные функции std::begin и std::end не определены.
Имея указатель, в общем случае, нельзя определить, указывает ли он на одиночный объект или на первый объект некоторой последовательности объектов. В виду этого нельзя определить функцию std::end для указателей, так как неизвестно число элементов, которые могут адресоваться указателем.
Вы могли бы свою функцию определить следующим образом
template bool in_array(T needle, T ( &haystack )[N] ) { auto e = std::find(std::begin(haystack), std::end(haystack), needle);
return e != std::end(haystack); }
Либо вы можете эту функцию определить как
template bool in_array(T needle, T *haystack, size_t n ) { auto e = std::find( haystack, haystack + n, needle);
return e != haystack + n; }
включив в объявление функции еще один параметр, задающий число элементов в массиве.

Программа потребляет много cpu

Небольшое отступление
У нас в фирме используется одна очень древняя программа с одним недостатком. После работы с ней надо чистить за ней файлы и в одном файле менять значения на первоначальные. Иначе при следующем запуске программа работает некорректно.
Итак решение - пишем программу в виде виндоуз формы, а потом форму удаляем, и кидаем ее в автозагрузку. В программе запущен таймер который проверяет если та древняя программа была закрыта пользователем он файлы приводит в первоначальный вид.
Но так форму я удалил (пользователям о ней знать не обязательно), что бы моя программа не завершала работу в ней стоит бесконечный цикл. Вот код:
private static void Main() { TimerCallback timer= new TimerCallback(Run);
System.Threading.Timer time = new System.Threading.Timer(timer, null, 0, 2000); for(;;) } static void Run(object state) {....}
но как оказалось он потребляет 20-30 процентов ресурсов проца именно из за бесконечного цикла. Есть у кого нибудь идеи как уменьшить нагрузку на проц?
Да и не хотелось бы использовать форму пусть и полностью прозрачную.


Ответ

Это у вас 3-4 ядра, вот оно и потребляет всего 20-30 процентов. Будет одно ядро - будет жрать 100, я думаю. Поставьте в этот цикл хотя бы Sleep(100) и будет счастье. А вообще надо нормально переписывать, а не костыли использовать...

Скобки () {} при инициализации внутри класса

Подскажите пожалуйста, а есть ли разница между использованием круглых и фигурных скобок при инициализации конструктора внутри класса. Оба варианта работают корректно.
class A { public: char c; int d;
A(char ch) :c(ch) {} A(char ch, int i) :c{ch}, d{i} {} };
int main() { A first = A('a'); A second = A('b', 1);
cout << "First: " << first.c << endl; cout << "Second: " << second.c << ' ' << second.d << endl;
return 0; }


Ответ

Начнем с того, что имеются случаи, когда нельзя применять инициализацию одного из видов к членам данных класса.
Например, если у вас имеется член класса, который является агрегатом (структурой или массивом), то возможные виды инициализации ограничены.
Рассмотрим несколько примеров.
В данном примере внутри структуры A объявляется агрегатный член данных B, имеющий тип структуры. Тогда данное объявление конструктора будет некорректныым
struct A { A(int x) : b( x ) {}
struct B { int x; } b; };
int main() { A a( 10 ); }
Компилятор выдаст сообщение об ошибке, говорящее о том, что он не может преобразовать объект типа int в объект типа struct B. Однако если вы замените круглые скобки на фигурные,
struct A { A(int x) : b{ x } {}
struct B { int x; } b; };
int main() { A a( 10 ); }
то код будет успешно компилироваться, так как объект b будет инициализирован как агрегат.
Теперь если в конструкторе заменить тип у параметра с int на A::B, то ситуация изменится.
Данная программа будет успешно компилироваться
struct A { struct B;
A(B x) : b( x ) {}
struct B { int x; } b; };
int main() { A::B b = { 10 }; A a( b ); }
так как структуры, которые являются агрегатами, имеют конструктор копирования, создаваемый компилятором неявно.
Иная ситуация складывается, когда членом данных, который представляет собой агрегат, является массив. Как и в случае со структурой, данная программа не будет компилироваться
struct A { struct B;
A(int x) : b( x ) {}
int b[1]; };
int main() { int b = 10; A a( b ); }
так как нет преобразования из целочисленного типа в массив.
Однако если заменить параметр на массив, не важно, является он ссылкой или нет, как показано ниже
struct A { struct B;
A(int x[1]) : b( x ) {}
int b[1]; };
int main() { int b[1] = { 10 }; A a( b ); }
или
struct A { struct B;
A(int ( &x )[1]) : b( x ) {}
int b[1]; };
int main() { int b[1] = { 10 }; A a( b ); }
то программа не будет компилироваться, так как в первом случае нет преобразования из указателя в массив, а во втором случае, когда параметр объявлен как ссылка, массивы не имеют конструктора копирования.
Для инициализации члена данных, который является массивом, можно использовать следующую запись
struct A { struct B;
A(int x) : b{ x } {}
int b[1]; };
int main() { int b = 10; A a( b ); }
Данная программа успешно скомпилируется. Однако вы не можете запись с фигурными скобками заключить еще в круглые собкки, как показано ниже
struct A { struct B;
A(int x) : b({ x }) {}
int b[1]; };
int main() { int b = 10; A a( b ); }
Компилятор выдаст сообщение об ошибке, так как, опять-таки, для массивов нет конструктора копирования. Однако для структур такая запись инициализации будет успешно воспринята компилятором, так как структуры, как агрегаты, имеют неявно объявленный компилятором конструктор копирования.
struct A { A(int x) : b({ x }) {}
struct B { int x; } b; };
int main() { int b = 10; A a( b ); }
Данная программа успешно скомпилируется.
Для арифметических типов инициализация с фигурными скобками не разрешает "сужение" значения, то есть использовать в качестве инициализатора значение, которое потенциально не может разместиться в инициализируемом объекте. Поэтому следующая программа не будет компилироваться
struct A { A(int x) : b{ x } {} short b; };
int main() { int b = 10; A a( b ); }
Причиной ошибки будет то, что объект типа short не в состоянии разместить все значения объекта типа int, то есть будет иметь место "сужение" инициализирующего значения.
Однако если заменить фигурные скобки на круглые, то программа успешно скомпилируется
struct A { A(int x) : b( x ) {} short b; };
int main() { int b = 10; A a( b ); }
Когда инициализируемый член класса является определенный пользователем тип, то в дело вступают конструкторы, которые имеют параметр типа std::initializer_list
Например, в приведенной ниже программе, когда нет такого конструктора, можно инициализировать член класса как b( x ), или как b{ x }, или даже как b( { x } )
struct A { A(int x) : b({ x }) {}
struct B { B(int x) { std::cout << "B( int )" << std::endl; } } b; };
int main() { int b = 10; A a(b); }
Однако если в классе присутствует конструктор с параметром типа std::initializer list, то для инициализаций вида b{ x } и b( { x } ) будет вызван именно он. А для инициализации вида b( x ) будет вызван другой конструктор.
Например, для этой программы
struct A { A(int x) : b( x ) {}
struct B { B(int x) { std::cout << "B( int )" << std::endl; } B(std::initializer_list) { std::cout << "B( std::initializer_list )" << std::endl; } } b; };
int main() { int b = 10; A a(b); }
будет выведено сообзение
B( int )
А для этой программы
struct A { A(int x) : b{ x } {}
struct B { B(int x) { std::cout << "B( int )" << std::endl; } B(std::initializer_list) { std::cout << "B( std::initializer_list )" << std::endl; } } b; };
int main() { int b = 10; A a(b); }
будет выведено сообщение
B( std::initializer_list )
Вообще, эта тема достаточно обширная.
О некоторых причудах инициализации я написал на своем сайте в конце темы Шутка - ложь, но в ней намек, добрым молодцам урок.

Корректировка анимации в Google Chrome

Задача перед мной стояла такая, скрыть 3 первых столбца в таблице, в итоге скрыл. Но отображение в Chrome странное, как только открываю страницу с таблицей примерно на 1 секунды появляются первые 3 столбца которые я скрыл, и как только 1 секунда проходит столбцы скрываются. Попробовал открыть в Мозиле там идеально работает, то есть открыл таблицу первых 3 столбцов не видно. Встречаюсь с таким впервые, как можно решить проблему ?
$(document).ready(function(){ $('#table td:nth-child(1)').css("display", "none"); $('#table td:nth-child(2)').css("display", "none"); ('#$table td:nth-child(3)').css("display", "none"); });


Ответ

Способ №1:
#table td:nth-child(1), #table td:nth-child(2), #table td:nth-child(3) {display:none;}

123

Способ №2:
$(function() { $('#table td:nth-child(1)').css("display", "none"); $('#table td:nth-child(2)').css("display", "none"); $('#table td:nth-child(3)').css("display", "none"); $('body').css("display", "block"); }); body {display:none;}
123

Освобождение памяти в Stack'e

Всем известно,что с Stack это некий участок памяти,который аллоцируется на каждый поток в виде размера 1МБ , в нем хранятся ссылки(ObjRef) на ReferenceType,пользовательские структуры,примитивные данные,ну и локальные переменные метода.
А теперь вопрос: что делает CLR, когда Stack полностью заполниться, и соответственно удалять по сути нечего.То бишь Stack переполнен?
Может ли CLR расширить его границы с 1МБ до 2МБ?(или это не возможно,в связи с чем,мы просто получим Exception, который оповестит нас о переполнении стека).
Другой вопрос: в контексте unsafe кода,unamanged участку памяти выделяется так же 1МБ или аллоцировать можно кастомный размер?


Ответ

Для начала стоит отметить что стек в момент выполнения кода - это не какой-то абстрактный safe-механизм. .NET использует JIT-компиляцию, так что в реальности выполняется код, привязанный к конкретной платформе, с использованием механизма стека этой платформы. В случае x86 - сегмент стека + пара регистров SS/ESP и операциями push/pop. Никакого отдельного стека для unsafe не создается.
Что происходит при заполнении стека и можно ли его увеличить по достижению лимита? Нет, в общем случае - нельзя.
Дело в том, что стек, по крайней мере в x86/64 - это структура данных, заполняемая с конца. Т.е. каждое помещение чего-то в стек сдвигает его указатель ближе к началу. Это идет из древних (еще до-.net) времен, когда памяти было мало, и стандартное разделение памяти выглядело так:
[код][данные-куча --> ....... пустое место....... <-- данные-стек]
Физическая память делилась между кучей и стеком, и у программиста всегда был выбор - выделить побольше памяти под что-то в куче, или положить побольше объектов в стеке. К тому же такая раскладка эффективно избавляла от необходимости контролировать размер отдельно кучи, и отдельно - стека. Т.к. если в ней куча и стек встретились - то памяти не осталось совсем.
С тех пор многое поменялось (хотя раскладка выше все еще актуальна на некоторых микроконтроллерах). В x86 Для стека теперь обычно выделен отдельный сегмент. Но он, по традиции, заполняется с конца. Т.е. каждая операция push уменьшает значение SP на размер положенного в стек.
По достижению ESP значения 0 - процессор выбрасывает ошибку. Механизма "довыделения памяти" в стеке в x86 нет - просто потому, что нельзя "довыделить" память в начало сегмента - а выделить память в конце и переложить все данные в стеке процессор не осмеливается - для него это слишком сложная операция. Это могла бы сделать операционная система, но по крайней мере Windows на x86 так не поступает.
На выходе по достижению 0 указателем стека вы получаете StackOverflowException в вашем коде .NET. Это индикатор достижения лимита "железного" стека, а не какого-то хитрого стека CLR.

Стоит отметить, что к StackOverflowException на x86 может привести также бесконечная рекурсия, причем даже в случае если вы не объявляете локальные переменные. Дело в том, что механизм вызовов методов на x86 (call) сохраняет в стеке адрес возврата из вызываемого метода. А оператор возврата (ret) достает адрес из стека. Поэтому слишком глубокая цепочка вызовов забивает стек.
Собственно, именно поэтому окно просмотра вызовов и называется Call Stack - информация цепочке возврата хранится только в стеке. Причем на x86 - в том же физическом стеке что и параметры фунций и локальные переменные.

В чём различие между jdk, sdk и j2sdk?

В чём заключается различие между JDK, SDK и J2SDK?


Ответ

SDK (software development kit) — набор инструментов для разработки приложений для определенной аппаратной/программной платформы.
JDK (java development kit) – набор инструментов для разработчика приложений на платформе и языке java (так как для платформы java можно писать приложения и на других языках программирования).
J2SDK (java 2 software development kit) – тоже что и JDK но название использовалось для версий 1.2.Х до 1.4.Х. С выходом java версии 1.2 было принято прибавлять цифру 2 к java для указания того что это следующая ступень развития языка/платформы. Добавление 2 продолжалось вплоть до версии java 1.5.0.12. С выходом java 1.5.0.12 двойку убрали.

В процессе развития платформы и языка java названия набор инструментов для разработки приложений (SDK) менялось:
1.Х использовалось название JDK, 1.2.Х по 1.5.11 – J2SDK в вперемешку с JDK, 1.5.12 по 1.8.X – JDK.
Более детально историю названия версий можно посмотреть здесь

Что за тип Class в Java?

Искал в интернете, но не нашел статей, чтобы разобраться что это за тип Class и с чем его едят. Что это за тип такой-то?


Ответ

В Java почти все сущности являются объектами, за исключением примитивных типов. У каждого объекта есть класс. Сами классы тоже является объектами, и они принадлежат классу Class.
У класса Class нет публичных конструкторов. Class - это generic тип. Методы Class предназначены для получения информации о классе (объекте типа Class). Например, можно узнать полное имя класса, какие у него аннотации, какие конструкторы и т.п. Эти методы нужны для reflection. С помощью reflection вы можете создавать объекты, которые принадлежат этому классу, и при этом заранее класс объекта вы можете не знать.
Существуют библиотеки, которые позволяют создавать объекты типа Class "на лету", т.е. вы можете создать новый класс прямо во время работы программы и так же можете изменить существующий класс.

C#. Можно ли перегрузить операторы сравнения в обобщенных классах?

Есть следующий обобщенный класс (он пока не реализован до конца):
class QuickSorter { private void Swap(ref Type a, ref Type b) { Type temp = a; a = b; b = temp; } public void Sort(Type[] Array) { //Sort_Recursion(Array); }
private void Sort_Recursion(Type[] Array, int L, int R) { /* Type Median = Array[L + (R - L)/2]; // (L + R)/2 = L/2 + R/2 = L - L/2 + R/2 = L + (R - L)/2 ==> Для избежания переполнения
int l = L; int r = R;
while (l <= r) { while (Array[l] < Median)
} */ }
public static bool operator >(Type a, Type b) {
}
public static bool operator <(Type a, Type b) {
}
}
Идея следующая: я хочу реализовать алгоритм быстрой сортировки для заданных типов данных (для целочисленных, вещественных, символьных). Хотел бы сделать это в одном классе. Подумал воспользоваться обобщенным классом, но в процессе написания кода столкнулся с проблемой сравнения переменных обобщенного типа. Перегрузка операторов для типа Type невозможна в классе QuickSorter. Есть ли способ реализовать перегрузку операторов сравнения для типа Type в обобщенном классе? Может быть, есть другое подходящее решение для данной задачи?


Ответ

В языке C# у свойств, индексаторов, событий, операторных методов, конструкторов и деструкторов не может быть параметров-типов. Однако их можно определить в обобщенном типе с тем, чтобы в их коде использовать параметры-типы этого типа. C# не поддерживает задание собственных обобщенных параметров типа у этих членов, поскольку создатели языка С# из компании Microsoft считают, что разработчикам вряд ли потребуется задействовать эти члены в качестве обобщенных. К тому же для поддержки обобщенного использования этих членов в С# пришлось бы разработать специальный синтаксис, что довольно затратно. Например, при использовании в коде оператора + компилятор может вызвать перегруженный операторный метод. Невозможно указать в коде, где есть оператор +, какие бы то ни было аргументы типа.

Примечание: В рекомендациях Microsoft для проектировщиков указано, что переменные параметров должны называться T или, в крайнем случае, начинаться с T (как, например, TKey или TValue). T означает тип (type), а I означает интерфейс (например, IComparable)

Как правильно заметил @Qwertiy:
Накладывать ограничения на статические члены C# не позволяет
А операторы сравнения должны быть статическими. Для решения проблемы можно наложить ограничение на класс, например class QuickSorter where T : IComparable, что ограничит использование классом только тех типов, в которых определен интерфейс IComparable
Все примитивные типы, кроме Object, Boolean, реализуют интерфейс IComparable и IComparable. Тип Boolean - реализует только IComparable
Что это дает? В операторах сравнения, вы вызываете метод CompareTo на сравниваемых экземплярах. Для примитивных типов все будет будет работать, для своих типов придется реализовать этот интерфейс.

Хотелось бы еще добавить: не используйте имя Type как имя обобщенного типа, поскольку этот тип определен в сборке mscorlib.dll, пространство имен System. В будущем может возникнуть недопонимание.

Разница между методом по умолчанию в интерфейсе и обычным методом в классе

Чем отличаются между собой метод по умолчанию, объявленный в интерфейсе с модификатором default и обычный метод, объявленный в обычном классе?
(update) Читаю
Метод по умолчанию представляет собой метод, который объявлен в интерфейсе с модификатором default; его тело всегда представлено блоком. Он предоставляет реализацию по умолчанию для любого класса, который реализует интерфейс без перекрытия метода. Методы по умолчанию отличны от конкретных методов, которые объявляются в классах.


Ответ

default метод не может обращаться к состоянию объекта (полям объекта), так как никакого объекта нет, но может вызвать другие методы и обращаться к статическим данным (константам).
default метод позволяет избежать необходимости изменить все классы, которые реализуют этот интерфейс.
В классе, реализующим интерфейс с default методами, вы можете их переопределить.
interface I1 { // это public static final int i = 0; // но в описании интерфейса public static final можно опустить int i = 0; default void m1() { System.out.println("I1 m1 i = " + i); m2(); }
void m2(); }
Без default этот класс бы не скомпилировался:
public class C1 implements I1 { @Override public void m2() { System.out.println("C1 m2"); }
public static void main(String[] args) { new C1().m1(); new C1().m2(); } }
Вывод будет следующим:
I1 m1 i = 0 C1 m2 C1 m2

Как в клиент-серверном приложении на сокетах узнать, что клиент завершил соединение?

Клиент какое-то время работает с сервером на сокетах. Клиент принимает решение завершить работу(например, аварийное завершение повисшего приложения).
Как узнать со стороны сервера, что сокет больше не валидный и можно его отбросить? socket.isClosed() на стороне сервера всегда возвращает false, даже если клиент уже вызвал socket.close() ?


Ответ

Метод isConnected поможет решить проблему. Возвращает TRUE, если клиент закрыл соединение.
public class MyServer { public static final int PORT = 12345; public static void main(String[] args) throws IOException, InterruptedException { ServerSocket ss = ServerSocketFactory.getDefault().createServerSocket(PORT); Socket s = ss.accept(); Thread.sleep(5000); ss.close(); s.close(); } }
public class MyClient { public static void main(String[] args) throws IOException, InterruptedException { Socket s = SocketFactory.getDefault().createSocket("localhost", MyServer.PORT); System.out.println(" connected: " + s.isConnected()); Thread.sleep(10000); int read = s.getInputStream().read(); if(read == -1) System.out.println("Socket disconnected"); else System.out.println(read); } }
ps. если не ошибаюсь, если клиент отключился, то Input/OutputStream-ы вернут IOException
UPD
isConnected() -правда, если сокет был успешно подключен к серверу. Закрытие сокета не очищает состояние соединения, что означает этот метод возвращает истину для закрытого сокета (см IsClosed ()), если он был успешно подключен еще до закрытия. isClosed() Возвращает закрытое состояние сокета. т.е. говорит вам закрыли ли вы этот сокет. Пока у вас есть, он возвращает ложь. isConnected() - если соединение закрыто, то read() вернет -1, если нет данных с потока, например, недоступен или дошли до конца потока. Этот метод блокирует поток до тех пор, пока не будет прочитан весь поток, либо не будет достигнуn конц потока, либо выбросит исключение. Замечание от @Regent: Если не указать timeout, то все зависнет на неизвестно сколько времени. readLine() вернет null
тогда нужно проверить состояние след. образом:
int read = s.getInputStream().read(); if(read == -1) System.out.println("disconnected"); else System.out.println(read);
p.p.s isConnected() не скажет отвалился ли клиент.

JavaScript Двойное отрицание(!!) и побитовый оператор Тильда (~)

Изучаю JavaScript. Задачка из учебника: Напишите функцию checkSpam(str), которая возвращает true, если строка str содержит „html“ или „css“, а иначе false. Функция должна быть нечувствительна к регистру:
Ответ из учебника:
function checkSpam(str) { var lowerStr = str.toLowerCase(); return !!(~lowerStr.indexOf('html') || ~lowerStr.indexOf('css')); } alert( checkSpam('hTml now') ); alert( checkSpam('free cSs') ); alert( checkSpam("more java") );
Вопросы:
Меня путает наличие сразу !! и ~ Как читается строка return? "Если не найдено, то вернуть ..." первый знак ! = Не, и приводим к логическому типу; дальше непонятки из-за ~ и второго отрицания. Вот мой вариант, он мне кажется понятнее:
function checkSpam(str) { var lowerStr = str.toLowerCase(); return (lowerStr.indexOf('html') != -1 || lowerStr.indexOf('css') != -1); } alert( checkSpam('hTml now') ); alert( checkSpam('free cSs') ); alert( checkSpam("more java") );
Есть ли в данных вариантах разница и какой вид более предпочтительный?


Ответ

Знак ! обозначает не
Если вы напишите return (~lowerStr.indexOf('html') || ~lowerStr.indexOf('css')), то оно просто выведет положение слов. Если вы введёте return !(~lowerStr.indexOf('html') || ~lowerStr.indexOf('css')), но оно выведет true/false, при том, что false выведется, если слово было найдено А когда вы вводите два !!, то оно выведет true, там где было false и наоборот
Знак ~ возвращает значение -(число + 1) Т.е. в вашем случае, если положение равно -1, то она выводит 0 и при этом в условии выводится false, а если другое любое число, то это true

Как можно максимально сократить этот код?

Морской бой. Пишу метод для поворота корабля.
tt - это текущее положение корабля:
0 - вертикально (по умолчанию) 1 - горизонтально (0 + 90°) 2 - вертикально (0 вверх ногами) 3 - горизонтально (0 - 90°)
ckw - это флаг поворота:
true - по часовой стрелке false - против часовой стрелки
Код метода поворота:
public void turn (boolean ckw) { if ((tt == 0 && !ckw) || (tt == 1 && ckw)) { //b -> c } else if ((tt == 1 && !ckw) || (tt == 2 && ckw)) { //c -> d } else if ((tt == 2 && !ckw) || (tt == 3 && ckw)) { //d -> a } else if ((tt == 3 && !ckw) || (tt == 0 && ckw)) { //a -> b } if (ckw) tt++; else tt--; }
Комментариями обозначены 4 цикла for-each с логикой разворота. Мне бы вот эту лесенку if-ов сократить. Это возможно?
Логика поворота
Корабль представляет собой ArrayList позиций в сетке. Например, 4-палубный, находящийся в середине поля: 35, 45, 55, 65. Чтобы его повернуть по часовой стрелке, надо прибавить к каждой позиции её индекс, умноженный на 11
b -> c (90° -> 180°) или (0° -> 270°)
for (int i = 0; i < col.size(); i++) { int num = col.get(i); int new_num = num + 11 * i; col.set(i, new_num); }
И т.д.


Ответ

Храним только базовые координаты, длину и текущее состояние разворота. Всё остальное вычисляемо из этих данных.
Демка на коленке:
public class Main { public static void main(String[] args) { Ship ship = new Ship(4, 1, 3, 5); // 35, ship.print(); System.out.println("Clockwise"); ship.turn(true).print(); ship.turn(true).print(); ship.turn(true).print(); ship.turn(true).print();
System.out.println("Counter-clockwise"); ship.turn(false).print(); ship.turn(false).print(); ship.turn(false).print(); ship.turn(false).print();
} }
public class Ship { private int state; private int x; private int y; private int length; public Ship(int length, int initialState, int x, int y) { state = initialState; this.x = x; this.y = y; this.length = length; }
public Ship turn(boolean clockwise) { if (clockwise) { state = (state + 1) % 4; } else { state = (state + 3) % 4; } return this; } public Ship print() { for (int i = 0; i < length; i++) { switch (state) { case 0: System.out.print("("+(10*x+y-i)+")"); break; // N case 1: System.out.print("("+(10*(x+i)+y)+")"); break; // E case 2: System.out.print("("+(10*x+y+i)+")"); break; // S case 3: System.out.print("("+(10*(x-i)+y)+")"); break; // W } } System.out.println(""); return this; } }

Хранение функции

Есть указатель на функцию, расположенную в DLL библиотеке. Можно ли эту функцию сохранить в объекте типа std::function<...> при корректном указании шаблонных параметров, затем отключить библиотеку через FreeLibrary (работаю в MSVC) и работать с функцией через std::function? Мне просто надо запихать туда разыменованный указатель на эту функцию?


Ответ

Т.е., простыми словами, что вы хотите сделать (вернее, что у вас получится) - вы сохраняете указатель на функцию, выбрасываете из памяти код функции, оставляя указатель непонятно куда, и вызываете ее... Как вы думаете, что у вас получится?
std::function тело функции никоим образом не сохраняет. Ну, а указатель на функцию будет инвалидирован вызовом FreeLibrary.
Набросать соответствующий код очень просто, можете убедиться сами...
indll.cpp
#include #include
using namespace std;
extern "C" void __declspec(dllexport) inDll() { cout << "From DLL
"; }
Компилируем как cl /LD indll.cpp
test.cpp
#include #include #include #include
using namespace std;
int main(int argc, const char * argv[]) { HMODULE dll; if (0 != (dll = LoadLibrary("inDll.dll"))) { cout << "Load success
";
FARPROC ptr = GetProcAddress(dll,"inDll"); function f = ptr; f(); FreeLibrary(dll);
} }
Компилируем как cl test.cpp
Запускаем test.exe, убеждаемся, что все работает. Меняем местами строки
f(); FreeLibrary(dll);
компилируем и убеждаемся окончательно, что так поступать нельзя :)

Как работают compound literals или внутреннее представление

Вероятно некоторые знают что такое compound literals и умеют использовать это на практике.
Однако у меня возник вопрос по внутреннему представлению этих литералов.
Ну предположим я имею такую запись: int *a = (int[]){10, 20, 30}; - таким образом я создал и присвоил указателю адрес созданного где-то в памяти массива типа int.
Можно ли предположить что запись: int *a = (int[]){10, 20, 30}; - эквивалентна следующей записи?
int arr[] = {10,20,30}; int *parr = arr;
По какой схеме идет присвоение адреса компаунд литерала?


Ответ

Да, можно так считать. Аналогия из двух объявлений вами составлена корректно.
Время жизни compound literal в точности определяется тем декларативным регионом, в котором он указан и совпадает с временем жизни обычной переменной того же типа, объявленной в том же контексте. То есть compound literal - это просто аналог безымянной переменной соответствующего типа с соответствующим инициализатором.

Однако с этим в языке С связана одна тонкость. До появления compound literals в С не существовало отдельного вопроса времени жизни объектов, объявленных, например, в ветках if
if (...) int a = 5; else int b = 42;
Так как объявления в языке С не являются и никогда не являлись statements, такой код является в С некорректным. Чтобы в С создать локальный декларативный регион, допускающий объявление переменных, необходимо явно использовать {}. То есть время жизни обычных (именованных) локальных объектов в С всегда очерчено явным блоком {} и полностью объясняется через свойства блока.
Однако с появлением в языке compound literals проблема времени жизни возникла вот в такой форме
int *a, *b, *c; if (a = (int []) { 1, 2, 3 }) b = (int []) { 4, 5, 6 }; else c = (int []) { 7, 8, 9 };
Каково должно быть время жизни таких compound literals? Должны ли они существовать после if?
До сих пор ни сам if, ни его ветки в языке С не являлись отдельными декларативными регионами - как сказано выше, в этом не было никакой необходимости. Однако после введения в язык compound literals в С99, было принято решение пойти по пути С++ и локализовать время жизни таких литералов. Теперь в С как сам if, так и его ветки, являются неявными блоками, ограничивающими время жизни созданных в них compound literals (и область видимости объявленных в них имен, см. ниже).
Т.е. теперь, начиная с С99, вышеприведенный if эквивалентен
int *a, *b, *c; { if (a = (int []) { 1, 2, 3 }) { b = (int []) { 4, 5, 6 }; } else { c = (int []) { 7, 8, 9 }; } }
со всеми вытекающими, т.е. с "повисшими" значениями указателей. Эта же модификация относится и к другим видам statements.
Это, кстати, привело к потере обратной совместимости с "классическим" С в ряде редко используемых контекстов. Например, в языке С разрешается объявлять новые типы в sizeof и в кастах. Пользуясь этой возможностью в С89/90 можно написать такой код
int foo(int a) { if (a == sizeof(enum { A })) a = sizeof(enum { B }); else a = sizeof(enum { C });
return a + A + B + C; /* ОК в С89/90. Ошибка в C99 */ }
После С99, из-за введения неявных блоков в if, такой код больше не компилируется.

Зачем нужен класс ThreadLocal в Java?

Поясните в общих чертах что это и с чем его едят, а после - может и ссылку годную на пример :)


Ответ

ThreadLocal — это тип, значение которого своё в каждом потоке.
Для чего такое может понадобиться? Если несколько сценариев.
Например, у вас есть приложение, которое пользуется различными библиотеками и фреймворками, цепочка вызовов уходит очень глубоко, и где-то там вызывает ваш callback. Вы хотели бы передать дополнительную информацию (например, права текущего юзера, или там просто кэш), но промежуточные фреймворки не протягивают через цепочку вызовов эту дополнительную информацию. Что делать? Можно воспользоваться статическими переменными, но что если ваше приложение многопоточное? За статические переменные будет конкуренция между потоками. Решение — кладите информацию на входе в ThreadLocal, на выходе в callback'е можно будет забрать.
Другой сценарий — это тот же кэш. В условиях многопоточной программы держать кэш потокобезопасным может оказаться дорого, ведь при этом каждое обращение к кэшу означает дорогую синхронизацию. Решение — завести по экземпляру кэша в каждом потоке, положив его в ThreadLocal
Похожий сценарий описан здесь: многопоточный доступ к SimpleDateFormat не разрешён, и чтобы не пересоздавать объект при каждом вызове, можно закэшировать его в ThreadLocal

Неправильное вычисление числа Pi в многопоточности

Всем привет, скажите пожалуйста почему у меня не правильно вычисляется число pi? То-есть есть примитивная формула и я её короче захотел просчитать, так вот, всё вроде-бы в один дополнительный поток работает хорошо, но я захотел чуть ускорить весь процесс (поэкспериментировать) и решил сделать просчёт суммы 6/n^2 в четырёх разных потоках, но к сожалению у меня вылетает не "3.141.... и т.д.", а какие нибудь совсем левые значения "4.76...", "2.34...", "1.13...". В чём может быть проблема ?
decimal sum = 0; decimal n = 0;
void func() { while (true) { n++; sum = sum + (6 / Convert.ToDecimal(n * n));
//Console.WriteLine("Поток " + Thread.CurrentThread.Name + " выводит " + n); } }
Thread myThread1; Thread myThread2; Thread myThread3; Thread myThread4;
private void button_Click(object sender, RoutedEventArgs e) {
myThread1 = new Thread(func); //Создаем новый объект потока (Thread) myThread1.Name = "Thread1"; myThread2 = new Thread(func); //Создаем новый объект потока (Thread) myThread2.Name = "Thread2"; myThread3 = new Thread(func); //Создаем новый объект потока (Thread) myThread3.Name = "Thread3"; myThread4 = new Thread(func); //Создаем новый объект потока (Thread) myThread4.Name = "Thread4"; myThread1.Start(); //запускаем поток myThread2.Start(); //запускаем поток myThread3.Start(); //запускаем поток myThread4.Start(); //запускаем поток }
private void button1_Click(object sender, RoutedEventArgs e) { label1.Content = (Math.Sqrt(Convert.ToDouble(sum))).ToString(); }


Ответ

Проблема в разделяемых данных. Дело с том, что ваши операции неатомарны, а выполнение потоков может пересекаться как угодно.
Представьте себе, что один поток стартовал и увеличил n, теперь n == 1. В этот момент другой поток стартовал, снова увеличил n (теперь n == 2), и прибавил к сумме (6 / Convert.ToDecimal(n * n));. Теперь первый поток продолжает выполнение, и прибавляет к сумме (6 / Convert.ToDecimal(n * n));. Но поскольку n уже успело увеличиться, будет прибавлено вовсе не то, что нужно!
Другая проблема, как подсказывает @Igor в комментарии — это то, что в коде sum = sum + (6 / Convert.ToDecimal(n * n)); значение sum может поменяться в другом потоке после вычисления правой части. Смотрите, пусть один поток вычислил значение sum + (6 / Convert.ToDecimal(n * n)) и хочет записать его в sum. В этот самый момент другой поток прибавляет к sum очередное слагаемое. Теперь возвращается к выполнению наш поток, и записывает в sum новое значение, теряя уже прибавленный другим потоком кусок!
Третья проблема — это неатомарность присваивания decimal. Дело в том, что decimal складывается не за один такт процессора, а значит, на середине сложения может вмешаться снова второй поток и всё испортить. Например, первое присвоение скопировало первое слово результата в переменную, тут прибежал второй поток и переписал новым значением все слова результата. Теперь первый поток продолжает запись, и записывает второе и дальнейшие слова — но первое слово получается вовсе от другого значения! Видите, сколько получается возможных проблем?

Есть несколько методов «бороться» с данными проблемами. Один из них — эксклюзивная блокировка данных на время работы с ними. Но ваш код состоит лишь из работы с разделяемыми данными, поэтому такая блокировка просто заставит все потоки ждать, пока один из них обрабатывает одну итерацию, тем самым задание будет выполнено ещё медленее, чем если бы его делал один поток!
Таким образом, имеет смысл изменить алгоритм, чтобы каждый поток работал лишь с локальными данными. Например, пусть один поток считает лишь каждое четвёртое слагаемое.
Получится примерно такой код:
decimal compute(int start, int step, int limit) { decimal sum = 0; for (long n = start; n < limit; n += step) sum += 6 / (decimal)(n * n); return sum; }

Task t0 = Task.Run(() => compute(0, 4, 100000)); Task t1 = Task.Run(() => compute(1, 4, 100000)); Task t2 = Task.Run(() => compute(2, 4, 100000)); Task t3 = Task.Run(() => compute(3, 4, 100000)); decimal result = await t0 + await t1 + await t2 + await t3; double pi = Math.Sqrt((double)result);

Для того, чтобы разобраться с тем, как работать с многопоточным кодом, стоит прочитать online-главу из книги братьев Албахари, или её русский перевод: глава 1, глава 2, глава 3, глава 4, глава 5.1, глава 5.2

Генерация формы множественного числа

Здравствуй, дали задачу по PHP
Напишите массив с числами от 1 до 30 [1, 2, 3 ....] и функцию, которая делает следующее проходит по массиву и каждому числу дописывает фразу "новых комментариев" и эти слова склоняются в соответствии с их числом и делает в итоге массив 1 новый комментарий 2 новых комментария и тд и вывести на экран в html в элементе
Прошу помочь с примерами решения, в PHP я новичок, теорию изучил не плохо но сижу несколько дней и не дошло пока что использовать в этом примере.


Ответ

Есть статья относительно множественных чисел. Там собраны алгоримы определения множественного числа для многих стран. Алгоритмы представлены в виде формул. Не нужно изобретать велосипед. Мы же используем формулы в математике.
В данном случае мы берем русский язык: nplurals=3 То есть для русского языка три множественные формы: 1) Когда элемент один. Например: 1 новый комментарий 2) Когда элементов больше двух, но меньше пяти. Например: 3 комментария, 4 комментария 3) Когда элементов больше или равно пяти. Например: 5 новых комментариев, 6 новых комменариев
Теперь перейдем к реализации. Условия привел в более читаемый вид:
$numbers = ['1', '2', '3', '4', '5'];
function plural($number) { if ($number % 10 == 1 && $number % 100 != 11) { return $number . ' новый комментарий'; } else { if ($number % 10 >= 2 && $number % 10 <= 4 && ($number % 100 < 10 || $number % 100 >= 20)) { return ($number . ' новых комментария'); } else { return ($number . ' новых комментариев'); } } }
foreach ($numbers as $number) { echo plural($number); echo '
'; }

удалить из Git файл большого размера попавший туда несколько коммитов назад

Опыт java и Git ~1 месяц, ОС linux mint.
Нужна ваша помощь:
1.В начале забыл добавить в .gitignore папку target/ в которой хранятся скомпилированные *.jar *.class и прочие файлы. 2.позже через несколько коммитов обнаружил что папка .git весит 12+ мегабайт, по размеру предполагаю что это забытый мной jar файл (кода у меня ~15 килобайт, все .class файлы ~14 килобайт) 3.нашел этот файл руками он весит 12 МБ и лежит в папке
.git/objects/pack/pack-2af1dfb851dabe3d606e0d0f9ad7ba84fd74f043.idx
Прошел несколько вопросов на русском и английском stackoverflow + google пробовал следующее:
git filter-branch --index-filter 'git rm --cached --ignore-unmatch FILENAME' --prune-empty -- --all git filter-branch --index-filter 'git rm --cached --ignore-unmatch FILENAME' HEAD git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch FILENAME' --prune-empty --tag-name-filter cat -- --all
Вместо FILENAME пробовал подставлять вот это:
target/gs-rest-service-0.1.0.jar gs-rest-service-0.1.0.jar target/ *.jar
толку не дало.
В итоге у меня 2 вопроса: -Как выяснить что это весит 12МБ в папке .git и как это удалить?
вот ссылка на мо проект на github, можно скачать как zip-архив или клонировать:
git clone https://github.com/jiraff537/tic-tac-toe-RESTfulWebService.git
(да я пытаюсь написать Rest-бэкэнд на Spring Boot'e для крестиков-ноликов)


Ответ

вы можете посмотреть содержимое каталога target (во всех коммитах):
$ git filter-branch --tree-filter 'ls -l target' Rewrite c05ea07d436c9e6c96f9e441bd469ae89d6383b4 (1/29)total 14056 drwxr-xr-x 3 user user 4096 May 23 14:27 classes -rw-r--r-- 1 user user 14352691 May 23 14:27 gs-rest-service-0.1.0.jar -rw-r--r-- 1 user user 3829 May 23 14:27 gs-rest-service-0.1.0.jar.original drwxr-xr-x 2 user user 4096 May 23 14:27 maven-archiver drwxr-xr-x 3 user user 4096 May 23 14:27 maven-status ...
или информацию о конкретном файле target/gs-rest-service-0.1.0.jar
$ git filter-branch --tree-filter 'ls -l target/gs-rest-service-0.1.0.jar' Rewrite c05ea07d436c9e6c96f9e441bd469ae89d6383b4 (1/29) -rw-r--r-- 1 user user 14352691 May 23 14:29 target/gs-rest-service-0.1.0.jar ...
удалить файл во всех коммитах можно, например, так:
$ git filter-branch --tree-filter 'rm -f target/gs-rest-service-0.1.0.jar' Rewrite f2133e7b3d7f209f43e88b802a6589cb2a1eadfd (29/29) Ref 'refs/heads/master' was rewritten

после такого переписывания истории в своём локальном репозитории вам придётся перезаписать историю и в репозитории на сайте github.com, добавив опцию -f (--force) команде push
$ git push -f

p.s. если репозиторий был склонирован ещё куда-то/кем-то, то там/тому надо будет принудительно переключиться на отправленную вами переписанную историю:
$ git fetch $ git reset --hard origin/master
или просто заново склонировать репозиторий в пустой каталог.

как это удалить?
после того, как вы перезаписали историю, объект типа blob, содержащий удалённый файл, стал «осиротевшим». чтобы удалить его, надо воспользоваться командой gc (gargabe collection):
$ git gc Counting objects: 500, done. Delta compression using up to 4 threads. Compressing objects: 100% (222/222), done. Writing objects: 100% (500/500), done. Total 500 (delta 221), reused 413 (delta 172)
как показывает вывод команды $ du -sb .git (выполненной до и после $ git gc), занимаемый каталогом .git объём изменился на 242997 байт (13254649-13011652). вероятно, именно столько занимал удалённый файл (в сжатом виде).
после того, как вы перезаписали свою локальную историю, удалённый файл (пока) не стал «осиротевшим» — на него есть ссылки из (пока не переписанной) истории подключенного репозитория (который на github-е находится). после того, как вы перепишете историю и на github-е, команда
$ git gc
должна будет удалить объект типа blob, содержащий этот «осиротевший» файл.
дополнение
полную очистку и упаковку всех объектов, чтобы добиться минимального размера каталога .git, можно выполнить примерно так:
$ git gc; git prune; git repack -ad
ваш репозиторий (т.е., содержимое каталога .git), после удаления того большого файла, и полной переупаковки, стал занимать у меня 187165 байт.

Неправильно работает поиск в Elasticsearch

Установил elastic. Настроил индексацию. Но в запросах какая-то странность выходит. Никак не пойму почему поиск некорректно работает
Я делал запросы с помощью либы в ruby, и пенял на нее, однако когда отснифал запрос понял что тут проблема в самом elastic. Да это даже не проблема, скорее фича.
prod = Post.search "ра", fields: [:title] // На выходе n-элементов prod = Post.search "разд", fields: [:title] // На выходе 0-элементов prod = Post.search "раздел", fields: [:title] // На выходе n-элементов
Скорее всего где то надо найти настройку, которая позволит улучшить поиск.


Ответ

Скорее всего, это поведение анализатора. ES использует немного более сложную схему поиска, нежели привычное точное совпадение:
При загрузке документа все текстовые поля пропускаются через анализатор, состоящий из токенайзера и фильтров Токенайзер бьет ввод на отдельные токены (как правило, это слова) Фильтры изменяют, добавляют и удаляют токены Токены записываются в конечный индекс При поиске запрос снова пропускается через анализатор, бьется на токены, и ES ищет совпадения между токенами запроса и токенами документа
Я подозреваю, что проблема именно в этом - в ES существуют токены "ра" и "раздел", но не существует токена "разд".
Скорее всего, дело именно в том, на какие токены разбивается запрос при поиске текущим анализатором. Чтобы проверить это, необходимо просмотреть токены совпадающих документов и токены запроса:
curl -XGET :9200//_analyze -d '{ "text": "разд" }'
curl -XGET :9200//_analyze -d '{ "text": "раздел" }'
curl -XGET :9200//_analyze -d '{ "text": "<текст документа>" }'
* В случае, если при поиске используется анализатор, отличный от анализатора индекса по умолчанию - скорее всего, вопрос это не подразумевает - его можно указать в поле "analyzer" * Токены документов можно получить напрямую из elasticsearch, но это немного сложнее
Если вы использовали все настройки по умолчанию, то у вас стоит стандартный анализатор, который (во всяком случае, у меня) даст следующие результаты:
Ра Разд Раздел
(причем я смог добиться поиска по последним двум запросам, но даже при ненормально больших fuzziness ES отказася находить мне что-либо по "ра", что подталкивает к тому, что либо у вас все-таки нестандартный анализатор, либо я полностью забыл эластик)
После этого вы можете посмотреть, как именно совпадает или не совпадает документ, с помощью explain API:
curl -XGET :9200////_explain -d '{ "query": { "query_string" : { "query": "ра" } } }'
* непосредственно запрос может отличаться и зависит от вашей библиотеки
Таким образом вы сможете найти причину этого поведения самостоятельно - со стороны коммьюнити это почти невозможно, пока вы не привели mapping соответствующего индекса в ES, документы, которые совпадает по двум из трех запросов, непосредственно сам запрос, который передает библиотека и версию ES. Однако, насколько я понимаю, конкретно за этим вопросом стоит необходимость сделать автокомплит - в этом случае вам нужен не поиск внутри ES, а suggester completion - это немного другой функционал ES, который создан именно для реализации автокомплита.

Скачать пакеты python для оффлайн установки

У меня на работе ограничения и если я скачиваю пакеты с помощью команды pip через командную строку, то с интернета все блокирует служба безопасности. Поэтому мне надо скачать пакеты напрямую, а потом установить в оффлайн режиме с компа. Но не могу найти где их скачать.
Подскажите где можно напрямую скачивать пакеты? Мне нужны tqdm, pandas, numpy, sklearn.metrics, statsmodels, scipy, matplotlib


Ответ

Скачивайте нужные вам пакеты отсюда https://pypi.python.org/ Для установки нужно написать pip install полный_путь_до_имени_файла

Отображение нескольких окон на несколько мониторов

При запуске приложения необходимо отобразить на 3 монитора - 3 разных окна. монитор А > окно А монитор Б > окно Б монитор В > окно В Примерно так.
Каким образом это можно реализовать на C# и WPF?


Ответ

Вот вариант БЕЗ WinForms
ScreenInformation.cs
namespace MultiScreen { public class ScreenInformation { [StructLayout(LayoutKind.Sequential)] public struct ScreenRect { public int left; public int top; public int right; public int bottom; }
[DllImport("user32")] private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lpRect, MonitorEnumProc callback, int dwData);
private delegate bool MonitorEnumProc(IntPtr hDesktop, IntPtr hdc, ref ScreenRect pRect, int dwData);
public class WpfScreen { public WpfScreen(ScreenRect prect) { metrics = prect; }
public ScreenRect metrics; }
static LinkedList allScreens = new LinkedList();
public static LinkedList GetAllScreens() { ScreenInformation.GetMonitorCount(); return allScreens; }
public static int GetMonitorCount() { allScreens.Clear(); int monCount = 0; MonitorEnumProc callback = (IntPtr hDesktop, IntPtr hdc, ref ScreenRect prect, int d) => { Console.WriteLine("Left {0}", prect.left); Console.WriteLine("Right {0}", prect.right); Console.WriteLine("Top {0}", prect.top); Console.WriteLine("Bottom {0}", prect.bottom); allScreens.AddLast(new WpfScreen(prect)); return ++monCount > 0; };
if (EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, callback, 0)) Console.WriteLine("You have {0} monitors", monCount); else Console.WriteLine("An error occured while enumerating monitors");
return monCount; } } }
App.xaml.cs
namespace MultiScreen { ///

/// Interaction logic for App.xaml /// public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); LinkedList screens = ScreenInformation.GetAllScreens(); foreach (var screen in screens) { var window = new MainWindow();
Console.WriteLine("Metrics {0} {1}", screen.metrics.top, screen.metrics.left);
window.Top = screen.metrics.top; window.Left = screen.metrics.left; window.Show(); } } } }

Передать в метод arrayList

есть три arrayList:
private ArrayList clothes = new ArrayList<>(); private ArrayList computers = new ArrayList<>(); private ArrayList smartphones = new ArrayList<>();
есть switch который в зависимости от выбранного передает в метод arraList:
switch (checkInt()) { case 1: searchName(clothes); break; case 2: searchName(computers); break; case 3: searchName(smartphones); break;}
собственно вопрос: как метод searchName должен принимать arrayList
searchName(???????????????){ }


Ответ

Максим,
сразу бросилось в глаза, что у вас тип переменно класс, а не интерфейс. Best практика советует использовать как раз-таки интерфейс, например:
private List clothes = new ArrayList<>(); private List computers = new ArrayList<>(); private List smartphones = new ArrayList<>();
Касательно Вашего вопроса, можно использовать generic методологию:
public void searchName(List list)
В вопросе неизвестно являются ли классы Clothes, Computer и Smartphone наследниками какого-то другого класса или интерфейса. Если бы они таки являлись, например:
interface Goods { int price(); int name(); int amount(); }
class Clothes implements Goods { ... }
class Computer implements Goods { ... }
То в таком виде код бы стал более лаконичным: Инициализация:
private static List clothes = new ArrayList<>(); private static List computers = new ArrayList<>();
Наполнение:
clothes.add(new Clothes()); computers.add(new Computers());
Метод остался бы унифицированным:
public void searchName(List list) { for (Goods entity : list) { System.out.println(entity.price()); } }
А вызов метода одинаковый для каждой из коллекций:
searchName(clothes); searchName(computers);
В худшем случае в варианте с generics можно будет определять какой именно объект пришел, используя instanceof оператор.

Разбиение Stream

Есть Stream, как разбить его на несколько Stream или List, относительно тех строк, которые начинаются с определенного слова (аналогично split("word") на обычной строке)?
Например, для "word":
[word, hello, dude, word and word2, stackoverflow, question, ask, word, example] => [[hello, dude], [stackoverflow, question, ask], [example]]
(Stream => Stream>)


Ответ

Можно собрать в Map по группам (группа -> список слов), а затем развернуть значения. Пример:
Stream src = Stream.of("word", "hello", "dude", "word and word2", "stackoverflow", "question", "ask", "word", "example"); final AtomicInteger group = new AtomicInteger(0); Stream> streamResult = src.map(s -> new AbstractMap.SimpleEntry<>(s, s.startsWith("word") ? 0 * group.incrementAndGet() - 1 : group.get())) .filter(entry -> entry.getValue() > -1) .collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList()))) .values().stream().map(List::stream);
Если нужен результат в виде List> то:
List> listResult = new ArrayList<>(src.map(s -> new AbstractMap.SimpleEntry<>(s, s.startsWith("word") ? 0 * group.incrementAndGet() - 1 : group.get())) .filter(entry -> entry.getValue() > -1) .collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList()))) .values());
Хотя в вашей ситуации непонятно зачем использовать именно stream-ы - проще просто проитерироваться по коллекции и собрать результат в нужном виде.

Как отнять подстроку у ID элемента

Хочу отнять подстроку у ID. Вот этот код выводит NaN
function someFunction(x) { var str = x.id; str = str - "Link"; alert(str); }

  • Должно остаться только my

  • Что я делаю не так? Есть ли решения лучше?


    Ответ

    Получить строку путём удаления из ID первого вхождения строки "Link" можно так:
    function someFunction(x) { var str = x.id.replace("Link", ""); console.log(str); }

  • Должно остаться только my

  • Тот же вариант с addEventListener вместо onclick
    document.addEventListener("DOMContentLoaded", function() { document.getElementById("myLink").addEventListener("click", function(event) { var str = event.target.id.replace("Link", ""); console.log(str); }); });
  • Должно остаться только my


  • Для удаления всех вхождений replace можно изменить:
    replace(/Link/g, "")

    Вообще говоря, в данной ситуации с единственным элементом с ID myLink с тем же успехом можно было просто сделать var str = "my";. Поэтому, для полноты картины, вариант с несколькими ссылками:
    document.addEventListener("DOMContentLoaded", function() { var links = document.getElementsByClassName("links"); for (var i = 0; i < links.length; i++) { links[i].addEventListener("click", function(event) { var str = event.target.id.replace("Link", ""); console.log(str); }); } });
    И, наконец, то же самое при использовании jQuery:
    $(function() { $(".links").on("click", function() { var str = this.id.replace("Link", ""); console.log(str); }); });

    Доступ к членам класса через .* и ->*

    В каких случаях используются операторы x.*ptm или p->*ptm? Прошу привести минимальный пример, где это может понадобиться. Да и вообще, где это реально может пригодится. Стоит ли использовать их? Можно ли их чем нибудь заменить?


    Ответ

    Вызывать подобным образом методы приходится ровно в том случае, если Вы сохранили указатель на этот метод :) Как это работает, описал @Harry, а вот зачем - это хороший вопрос.
    Нередко возникает ситуация, когда программисты хотят упростить себе жизнь (ленивые же). Написали Вы, например, такой код:
    #include
    enum class State { One, Two, Three };
    class A { State _cur_state; public: A(State s) : _cur_state(s) {}
    void DoSomething() { switch (_cur_state) { case State::One: std::cout << "Foo" << std::endl; break; case State::Two: std::cout << "Bar" << std::endl; break; case State::Three: std::cout << "Baz" << std::endl; break; } }; };
    int main() { A(State::One).DoSomething(); }
    Через некоторое время придёт осознание того, что проще-таки написать
    class A { State _cur_state; public: A(State s) : _cur_state(s) {}
    void DoSomething() { static std::unordered_map state_to_string { { State::One, "Foo" }, { State::Two, "Bar" }, { State::Three, "Baz" } };
    std::cout << state_to_string[_cur_state] << std::endl; }; };
    Через некоторое время оказывается, что в caseах должен быть какой-то замудреный код и Вы возвращаетесь к первоначальному варианту, переместив этот код в методы:
    class A { State _cur_state;
    void DoFoo() { /* code */ } void DoBar() { /* code */ } void DoBaz() { /* code */ } public: A(State s) : _cur_state(s) {}
    void DoSomething() { switch (_cur_state) { case State::One: DoFoo(); break; case State::Two: DoBar(); break; case State::Three: DoBaz(); break; } }; };
    Но потом Вы вспоминаете про указатели на методы и код вновь становится чистым!
    class A { State _cur_state;
    void DoFoo() { /* code */ } void DoBar() { /* code */ } void DoBaz() { /* code */ } public: A(State s) : _cur_state(s) {}
    void DoSomething() { static std::unordered_map state_to_method { { State::One, &A::DoFoo }, { State::Two, &A::DoBar }, { State::Three, &A::DoBaz } };
    (this->*state_to_method[_cur_state])(); }; };
    P.S. Обработку ошибок не писал.
    P.P.S. В случае enumов быстрее будет вариант с вектором или первоначальный, но данный пример для академических целей.

    Сравнение двух .txt

    Есть 1.txt и 2.txt в каждом есть около 10КК+ строк, но == длинны. Каким методом можно максимально быстро найти одинаковые строки из 1.txt во втором, то есть найти те строки из 2.txt, которые будут также в 1.txt
    1.txt 1 2 3 4 5 6 7 (пробел типа энтера)
    2.txt 9 0 9 9 9 1

    значит во втором только одно совпадение есть "1" ?


    Ответ

    Если строки в файлах уже отсортированы, то задача значительно упрощается.
    Воспользуемся итераторами:
    var s1 = File.ReadLines("1.txt"); // Обратите внимание не ReadAllLines, var s2 = File.ReadLines("2.txt"); // а ReadLines using (var en1 = s1.GetEnumerator()) // Берем using (var en2 = s2.GetEnumerator()) // итераторы { if (en1.MoveNext() && en2.MoveNext()) { while (true) { var w1 = en1.Current; // Берем по var w2 = en2.Current; // элементу var comp = w1.CompareTo(w2); if (comp == 0) // Нашли совпадение Console.WriteLine(w1); if (comp <= 0) // Выбираем какой из указателей сдвинуть if (!en1.MoveNext()) break; // Выход если нечего больше брать if (comp >= 0) if (!en2.MoveNext()) break; } } }

    Тоже самое, но работаем с потоками явно:
    using (var sr1 = new StreamReader("1.txt")) using (var sr2 = new StreamReader("2.txt")) { var w1 = sr1.ReadLine(); var w2 = sr2.ReadLine(); while (w1 != null && w2 != null) { var comp = w1.CompareTo(w2); if (comp == 0) Console.WriteLine(w1); if (comp <= 0) w1 = sr1.ReadLine(); if (comp >= 0) w2 = sr2.ReadLine(); } }

    Примечания:
    При сравнении строк много нюансов и если CompareTo вернул 0, то есть ненулевая вероятность того, что Equals или == покажут что строки не равны [Албахари, C# 6.0 Справочник: Полное описание языка, стр. 292]. Также, желательно, использовать компаратор, который был использован при сортировке строк, размещенных в файлах, так как разные компараторы могут давать разный результат [Сортировка массивов русских символов и строк с участием буквы Ё].

    Не работает “hidden” в bootstrap 4

    Не скрывает элементы в bootstrap 4, при подключении bootstrap 3 все работает хорошо

    Example

    Resize this page to see how the text below changes:

    This is text hidden on a MEDIUM screen.


    Ответ

    В beta версии в очередной раз все переиграли и теперь группа классов имеет вид:
    .d-*-none
    Стоит так же обратить внимание, что теперь условия применяются не на конкретный диапазон, например, только на medium, а на medium и больше. Поэтому был убрал класс с xs, так как сейчас это эквивалентно не показываться на экранах xs и больше, что означает - никогда не показывать.
    Пример:

    Example

    Resize this page to see how the text below changes:

    This text is hidden on an EXTRA SMALL screen and larger.
    This text is hidden on a SMALL screen and larger.
    This is text hidden on a MEDIUM screen and larger.
    This is text hidden on a LARGE screen and larger.

    Динозаврик гугла [закрыт]

    Можно ли написать на С++ динозаврика гугловского? (это который появляется,когда нет интернет-соединения)
    Может быть где-то есть открытый код на эту игру?..


    Ответ

    Да, можно. Код есть в репозитории chromium: T-Rex runner

    jQuery: не получается вырезать и вставить элемент во второй раз

    Дано: контейнер с тремя элементами. Задача: взять первый элемент и переместить его в конец контейнера (будет последовательность 2, 3, 1), затем сделать ещё раз то же самое для ставшего первым элемента (будет в результате 3, 1, 2).

    В приведённом ниже решении первый раз всё срабатывает успешно:
    $container.append($allElements.first());
    Если дублировать эту строку и выполнить код, то перемещения до последовательности (3, 1, 2) уже не произойдёт. Возможно, я неправильно понял ранее изученное, но вроде как jQuery-объект меняет своё состояние, когда происходят какие-то изменения с соответствующими ему элементами DOM.
    Пытаюсь снова сделать выборку вместо уже имеющегося объекта $container
    $('.container').append($allElements.first());
    Тоже ничего не происходит. Объясните, пожалуйста, причины этого.
    P. S. Можно решить поставленную задачу через замысловатые условия и арифметические операции, но стремясь к простоте кода, хотелось бы работать только в первым элементом $allElements.first() (в каждой итерации).
    let $container = $('.container'); let $allElements = $('.element'); $container.append($allElements.first()); //$container.append($allElements.first()); // не работает //$('.container').append($allElements.first()); // так тоже .container { display: inline-block; background: rgba(255, 0, 0, 0.25); line-height: 1; } .element { display: inline-block; width: 100px; height: 100px; } .element-first { background: rgba(255, 255, 0, 0.25); } .element-second { background: rgba(0, 128, 0, 0.25); } .element-third { background: rgba(0, 0, 255, 0.25); }

    1
    2
    3


    Ответ

    Коллекция в jQuery - это НЕ живая коллекция, поэтому, пока руками ее не модифицируешь, в ней ничего не поменяется.
    Поэтому в твоем коде ты постоянно добавляешь один и тот же элемент.
    В качестве решения в лоб, можно просто заново получать все элементы, хотя на самом деле, тебе нужен только первый.
    Например так:
    let $container = $('.container'); $container.append($('.element:first-child')); $container.append($('.element:first-child')); .container { display: inline-block; background: rgba(255, 0, 0, 0.25); line-height: 1; } .element { display: inline-block; width: 100px; height: 100px; } .element-first { background: rgba(255, 255, 0, 0.25); } .element-second { background: rgba(0, 128, 0, 0.25); } .element-third { background: rgba(0, 0, 255, 0.25); }

    1
    2
    3

    Сортировка массива структур по нескольким полям

    Решил задачу, вопрос на которую ранее сам задавал, хочу поделиться.
    Задача: есть структура. У структуры три поля: фамилия (char) , имя(char), год рождения (int).
    Массив таких структур нужно отсортировать по каждому полю. Т.е. сначала все элементы сортируем по фамилии, затем их сортируем по имени, и потом по году. Сначала у нас идут все элементы с фамилией на А, именем на А и минимальным годом рождения среди тех у кого фамилия и имя на А... затем все с фамилией на В, именем на В и минимальным годом рождением среди тех у кого имя и фамилия на В... Это общий принцип.
    Массив структур автомобилей:
    struct Car { int idCar = 0; //порядковый номер элемента массива структур (id) int size = 0; //размер элемента структур char regNum[7]; //поле с регистрационным номером char markCar[10];//марка автомобиля char modelCar[10]; //модель автомобиля int mileAge = 0; //пробег автомобиля int isEmpty = 0; //индикатор, если поля марка, модель, рег. номер и пробег пустые, то == 0 };
    Функция по расширению, добавлению нового элемента в конец массива структур:
    void addCar(Car *cars) {
    int N = cars->size; N += 1; int id = N - 1; *cars = *(Car*)realloc(cars, (N+1) * sizeof(Car)); for (int i = 0; i < N; i++) { (cars+i)->size = N; } (cars + id)->idCar = id; (cars + id)->isEmpty = 0; for (int i = 0; i<10; i++) (cars + id)->markCar[i] = '\0'; (cars + id)->mileAge = 0; for (int i = 0; i<7; i++)(cars + id)->regNum[i] = '\0'; for (int j = 0; j<10; j++) (cars + id)->modelCar[j] = '\0'; }
    Функция по поиску структурированной переменной с наименьшим значением поля пробег:
    void minMileAge(Car *cars) { int min = INT_MAX; for (int i = 0; i < cars->size; i++) { if (min > (cars + i)->mileAge) min = (cars + i)->mileAge; } for (int j = 0; j < cars->size; j++) { if (min == (cars + j)->mileAge && (cars + j)->mileAge != 0) { printf("%d
    ", (cars + j)->idCar); printf("Регистрационный номер: %s
    ", (cars + j)->regNum); printf("Марка автомобиля: %s
    ", (cars + j)->markCar); printf("Пробег автомобиля: %d
    ", (cars + j)->mileAge); } } }
    Функции для сравнения структурированных переменных типа Car:
    int my_strcmp(char *s1, char *s2) { for (; *s1 != '\0' && *s2 != '\0' && (*s1 == *s2); s1++, s2++); return *s1 - *s2; } int cmpCar(Car *t1, Car *t2) { int result; if ((result = my_strcmp(t1->markCar, t2->markCar))) return result; if((result = my_strcmp(t1->modelCar, t2->modelCar))) return result; if (result = (t1->mileAge - t2->mileAge)) return result; return my_strcmp(t1->regNum, t2->regNum); }
    Функция сортировки массива структур типа Car по 4 полям (методом вставок):
    void sortCar(Car *cars) { for (int i = 1; i < cars->size; ++i) { Car x = *(cars+i); int j = i; while (j > 0 && cmpCar((cars + j - 1), &x)>0) { *(cars+j) = *(cars + j - 1); j = j - 1; } *(cars + j) = x; } for(int l = 0; lsize; l++) { printf("ID номер автомобиля %d
    ", (cars + l)->idCar); printf("Марка автомобиля: %s
    ", (cars + l)->markCar); printf("Модель автомобиля: %s
    ", (cars + l)->modelCar); printf("Пробег автомобиля: %d
    ", (cars + l)->mileAge); printf("Регистрационный номер: %s
    ", (cars + l)->regNum); } }
    И функция поиска элемента из массива структур, по полю, содержащему искомую подстроку:
    void allCar(Car *cars) { int result; char sbm[10]; printf("%s", "Введите значение для поиска: "); scanf("%s", &sbm); for (int i = 0; i < cars->size; i++) { if ((strstr((cars + i)->markCar, sbm)!=NULL || (strstr((cars + i)->modelCar, sbm))!=NULL || (strstr((cars + i)->regNum, sbm)!=NULL))) { printf("id автомобилей содержащих значение %d
    ", (cars + i)->idCar); }
    } }


    Ответ

    Реализация на C - обычный qsort, только функция сравнения должна быть немного сложнее, только и всего. Для типа наподобие
    typedef struct Person { char f[20]; char n[20]; int y; } Person;
    имеем
    int comp(const void * ptr1, const void * ptr2) { Person * p1 = (const Person*)ptr1; Person * p2 = (const Person*)ptr2;
    int cmp = strcmp(p1->f, p2->f); if (cmp) return cmp;
    int cmp = strcmp(p1->n, p2->n); if (cmp) return cmp;
    return p1->y - p2->y; }
    Примерно так. Писал "на коленке", не комппилируя - просто показать принцип. Сравниваете по первому полю, при равенстве - по второму, при равенстве - по третьему.
    И никаких трех сортировок...

    Почему в первом коде не нужен нулевой символ?

    У нас есть функция которая принимает две строки и производит слияние
    void strcat(char *to, const char *from) { while (*to) to++; while (*to++ = *from++); }
    Почему здесь не требуется добавить нулевой символ в отличие например от такого кода
    void strcat(char *to, const char *from) { while (*to != '\0') { to++; }
    while (*from != '\0') { *to = *from; from++; to++; } *to = '\0'; }


    Ответ

    Нулевой символ здесь добавляется автоматом.
    Выражение
    *to++ = *from++
    выполняет присвоение, после чего возвращает новое значение *to. То есть, сначала ноль скопируется из *from в *to, а уж потом он будет проанализирован в while, который прекратится.

    переменная errno в многопоточной программе

    здравствуйте, допустим, в нескольких программных нитях(потоках) вызываем функцию read... и она завершается в одном из нитей, допустим, с errno = EAGAIN, в другой с errno = EBADF... потокобезопасна ли переменная errno, или в каждой нити она своя?


    Ответ

    Короткий ответ -- да, errno потокобезопасна. Это требование Posix. (смотри этот ответ)

    mysqli вывод по одной записи

    Добрый день. Есть база такого формата
    Структура: id - цифры (идут не всегда по порядку) text - mediumtext (тут какая то цитата)
    Задача в том, чтобы выводить их по очереди по 1 записи. А точнее при нажатии кнопки "Следующая" должна вывестись следующая запись с базы данных. Так как id не всегда по порядку, то столкнулся с проблемой реализации, так как с БД еще мало знаком.


    Ответ

    Вам стоит прочитать про это http://postgresql.ru.net/manual/queries-limit.html
    $sql = 'SELECT `id`, `text` FROM `comments` WHERE 1 LIMIT 1 OFFSET.$page;
    Вообще советую не пилить велосипед и использовать Doctrine
    http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html
    Так как запросы в php весьма сложны в обслуживании.

    Есть ли возможность отключить assert?

    Собственно и весь вопрос в заголовке.
    Если такой возможности нет, то не пойму, в чем ценность такой инструкции как assert вообще?
    А то как-то все неубедительно. Ведь можно простыми if ...: print() в одну строку обойтись... P.S: я уже получил ответ от andreymal, однако интересно отключить assert первой строчкой в коде... возможно ли это? Ведь os.environ читается до первой строчки модуля...


    Ответ

    assert, в отличие от if, предназначен для обнаружения ситуаций, которые задумывались как в принципе невозможные в программе: для поиска багов. Отключать assert обычно не стоит, но для ускорения программы это иногда может быть полезным.
    Для его отключения есть несколько способов.
    Для отдельного Python-процесса
    Использование флага -O (большая латинская O) включает базовую оптимизацию и отключает все assertы в данном процессе.
    Пример:
    $ python -Oc "assert False"
    $ python -c "assert False" Traceback (most recent call last): File "", line 1, in AssertionError
    Для окружения
    Можно использовать переменную окружения для установки этого флага. Тогда он будет применён ко всем процессам, использующим данное окружение.
    Например, установка и очистка переменной окружения в Windows:
    C:\>python -c "assert False" Traceback (most recent call last): File "", line 1, in AssertionError C:\>SET PYTHONOPTIMIZE=TRUE
    C:\>python -c "assert False"
    C:\>SET PYTHONOPTIMIZE=
    C:\>python -c "assert False" Traceback (most recent call last): File "", line 1, in AssertionError
    Для конкретного места в коде
    Когда выражение, прописанное в assert, ложно, выбрасывается исключение AssertionError. Если ожидается, что такой-то assert провалится, можно просто перехватить это исключение:
    >>> try: ... assert False, "мы знаем, что это упадёт" ... except AssertionError as e: ... print(repr(e)) ... AssertionError('мы знаем, что это упадёт',)
    После такого перехвата исключения, если вы не выбросите новое исключение, программа продолжит выполняться дальше.
    (Впрочем, так делать плохо: если assert провалился, нужно принять все меры по исправлению программы так, чтобы он больше не проваливался, а не скрывать возможный баг таким костылём.)
    Дополнительная информация
    Из документации assert
    Выражение с assert, вроде такого:
    assert expression #, optional_message
    Эквивалентно такому коду:
    if __debug__: if not expression: raise AssertionError #(optional_message)
    И
    встроенная переменная __debug__ имеет значение True в обычных условиях и False, если включены оптимизации (аргумент командной строки -O).
    Из документации по использованию python
    -O Включает базовые оптимизации. См. также PYTHONOPTIMIZE
    и
    PYTHONOPTIMIZE Если эта переменная является непустой строкой, это аналогично использованию опции -O. Если в переменной указано целое число, это аналогично добавлению опции -O несколько раз.

    Слегка вольный перевод ответа от Aaron Hall на enSO

    заменить строки в одном текстовом файле информацией из второго

    Именются 2 гигантских текстовых файла.
    file1.txt (3,6 Гб) содержит только одну колонку (в том числе много дубликатов):
    123456 123456 123456 абвгд абвгд 01щенок 01щенок 01щенок 01щенок 01щенок a0125uß a0125uß
    file2.txt (1,5 ГБ) содержит ту же колонку, но без дубликатов плюс вторую колонку.
    123456:artur абвгд:sergey 01щенок:max a0125uß:stasik
    Задача: сравнить первые колонки в обеих файлах и заменить одинаковые строки в первом файле, строками из второй колонки второго файла, чтобы получилось следующее (дубликаты в первом файле должны остаться):
    artur artur artur sergey sergey max max max max stasik stasik
    У меня есть такой код:
    import io STRFILE1 = 'file1.txt' STRFILE2 = 'file2.txt' STRFILERESULT = 'result.txt' fIN = open(STRFILE1,'r') strContent = fIN.read() fIN.close()
    with open(STRFILE2,'r') as f: for line in f: mapping = line.split(":",1) strContent = strContent.replace(mapping[0],mapping[1].rstrip("
    "))
    fOUT = open(STRFILERESULT,'w') fOUT.write(strContent) fOUT.close()
    но он работает вечно с таким объёмом строк (102.600.000 - файл 1 и 50.000.000 - файл 2). Как можно ускоритъ процесс обработки?


    Ответ

    Если на python, то можно так:
    def story_key(): with open('te2', 'r') as f2: my_key = {i.split(':')[0]: i.split(':')[1].strip() for i in f2} return my_key
    all_key = story_key()
    def read_small(f_object, f_size=1024): while True: data = f_object.read(f_size) if not data: break yield data
    def f_write(): with open('te1') as f1: with open('te3', 'a') as f3:
    for i in read_small(f1): a = [all_key[j] + '
    ' for j in i.split('
    ') if j] f3.write(''.join(a))
    f_write()

    Многопоточность в java, почему порядок вывода результата разнится?

    Допустим есть такой код. Его результат:[Синхронизация] [в Java] [ полезная] . Если объект Caller запускать без отдельного потока (т.е без "extends Thread" и без метода "start()"), то результат будет в другом порядке- [Синхронизация] [полезная] [в Java] Почему так происходит? Прошу дать развернутый ответ.
    class CallMe{ void call(String msg){ System.out.print("[" + msg ); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("]"); } }
    class Caller extends Thread{ String msg; CallMe target;
    Caller(CallMe target, String msg){ this.target = target; this.msg = msg; start(); }
    public void run(){ synchronized (target) { target.call(msg); } } }
    public class Main { public static void main(String[] args) { CallMe callMe = new CallMe(); new Caller(callMe, "Синхронизация"); new Caller(callMe, "в Java"); new Caller(callMe, " полезная"); } }


    Ответ

    Поставьте задержку на 200 миллисекунд в методе run(), а в методе main() добавьте цикл операций на 100 - получите еще больше вариантов.
    Потому что невозможно предсказать какой поток войдет в блок synchronized первым, даже если вы их запускаете последовательно.
    Для синхронизации потоков используются классы
    Semaphore CountDownLatch CyclicBarrier Lock
    у них различные цели и методы. Это зависит от конкретной задачи.

    Semaphore - как правило служит для ограничения количества потоков при работе с ресурсами. Доступ ограничивается с помощью счетчика, если его значение больше нуля, то доступ потоку разрешается, а значение счетчика уменьшается. Если счетчик равен нулю, то текущий поток блокируется, пока другой поток не освободит ресурс. Для получения доступа используется метод acquire(), для освобождения – release()
    public class SemaphoreDemo { public static void main(String[] args) { Semaphore smp = new Semaphore(2); for (int i = 0; i < 5; i++) { final int w = i; new Thread(() -> { try { System.out.println("Поток" + w + " перед семафором"); smp.acquire(); System.out.println("Поток" + w + " получил доступ к ресурсу"); Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } finally { System.out.println("Поток" + w + " освободил ресурс"); smp.release(); } }).start(); } } }
    Результат работы:
    Поток 0 перед семафором Поток 0 получил доступ к ресурсу Поток 2 перед семафором Поток 2 получил доступ к ресурсу Поток 1 перед семафором Поток 4 перед семафором Поток 3 перед семафором Поток 2 освободил ресурс Поток 1 получил доступ к ресурсу Поток 0 освободил ресурс Поток 4 получил доступ к ресурсу Поток 4 освободил ресурс Поток 1 освободил ресурс Поток 3 получил доступ к ресурсу Поток 3 освободил ресурс
    Одновременно семафор могут захватить(с помощью метода acquire()) только два потока, остальные потоки становятся в очередь, пока один из потоков не освободит семафор методом release()

    CountDownLatch - Позволяет потоку ожидать до тех пор, пока не завершится определенное количество операций, выполняющихся в других потоках, в режим ожидания поток заходит с помощью метода await(). Количество требуемых операций задается при создании объекта, после чего уменьшается при вызове метода countDown(). Как только счетчик доходит до 0, ожидающий поток разблокируется.
    public class SimpleCDL { public static void main(String[] args) { // задаем кол-во потоков final int THREADS_COUNT = 6; // задаем значение счетчика final CountDownLatch cdl = new CountDownLatch(THREADS_COUNT); System.out.println("Начинаем"); for (int i = 0; i < THREADS_COUNT; i++) { final int w = i; new Thread(() -> { try { // считаем что выполнение задачи занимает ~1 сек Thread.sleep(500 + (int)(500 * Math.random())); // как только задача выполнена, уменьшаем счетчик cdl.countDown(); System.out.println("Поток #" + w + " - готов"); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } try { // ждем пока счетчик не сбросится в ноль, пока это не // произойдет, будем стоять на этой строке cdl.await(); } catch (InterruptedException e) { e.printStackTrace(); } // как только все потоки выполнили свои задачи - пишем сообщение System.out.println("Работа завершена"); } }
    Результат работы:
    Начинаем Поток #1 - готов Поток #0 - готов Поток #3 - готов Поток #2 - готов Поток #4 - готов Поток #5 - готов Работа завершена
    Основной поток создает 6 потоков и ждет пока каждый из этих потоков закончит приготовление к работе.

    CyclicBarrier - используется для синхронизации заданного количества потоков в одной точке. При вызове метода await() поток блокируется. Как только заданное количество потоков заблокировалось, с них одновременно снимается блокировка.
    public class BarrierExample { public static void main(String[] args) { CyclicBarrier cb = new CyclicBarrier(3); for (int i = 0; i < 3; i++) { final int w = i; new Thread(() -> { try { System.out.println("Поток " + w + " готовится"); Thread.sleep(100 + (int) (3000 * Math.random())); System.out.println("Поток " + w + " готов"); cb.await(); System.out.println("Поток " + w + " запустился"); } catch (Exception e) { e.printStackTrace(); } }).start(); } } }
    Результат работы:
    Поток 0 готовится Поток 1 готовится Поток 2 готовится Поток 2 готов Поток 0 готов Поток 1 готов Поток 1 запустился Поток 2 запустился Поток 0 запустился Результат работы: Поток 0 готовится Поток 1 готовится Поток 2 готовится Поток 2 готов Поток 0 готов Поток 1 готов Поток 1 запустился Поток 2 запустился Поток 0 запустился
    Несмотря на то, что какие-то потоки закончили подготовку раньше, какие-то позже, стартовали они в одно и то же время, так как блокировка снимается одновременно. Несмотря на то, что какие-то потоки закончили подготовку раньше, какие-то позже, стартовали они в одно и то же время, так как блокировка снимается одновременно.

    Lock - Интерфейс. Представляет собой продвинутый механизм синхронизации потоков, который предоставляет большую гибкость чем блоки синхронизации. Поскольку Lock это интерфейс, для работы с ним необходимо создать объект одной из его реализаций.
    Lock lock = new ReentrantLock(); lock.lock(); lock.unlock();
    В начале создается объект типа Lock, после чего у этого объекта вызывается метод lock() и он захватывается. Попытка другого потока вызвать у этого же объекта метод lock() приведет к блокировке этого потока, пока поток удерживающий объект lock не освободит его с помощью метода unlock(). После вызова метода unlock() объект типа Lock освобождается и другие потоки могут его захватить Основные отличия между Lock и синхронизированными блоками:
    Синхронизированные блоки не гарантируют сохранность порядка обращения потоков к критической секции; Выйти из синхронизированного блока по времени ожидания(timeout) не получится; Синхронизированные блоки должны полностью содержаться в одном методе, в то время как Lock может быть захвачен в одном метода, а освобожден в другом.