Страницы

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

четверг, 19 декабря 2019 г.

произвести замену в шаблоне по условию

#python #python_3x #format


Нужно сформатировать строку (желательно методом format). Строка, например, такая:

string = "words{hello||hello1}words"


А до этой строки задается параметр s=True или s=False, и если s=True, то на выходе
должна получиться вот что:

string = 'wordshellowords'


, а если s=False, то:

string = 'wordshello1words'


Как это сделать?
    


Ответы

Ответ 1



Алгоритм по шагам: string = "words{hello||hello1}words" start = string.index('{') + 1 end = string.index('}') replace_str = string[start: end] print(replace_str) # hello||hello1 var_replace = replace_str.split('||') print(var_replace) # ['hello', 'hello1'] string = string.replace(replace_str, '') print(string) # words{}words s = True if s: new_string = string.format(var_replace[0]) print(new_string) # wordshellowords else: new_string = string.format(var_replace[1]) print(new_string) # wordshello1words В виде функции: def foo(string: str, s=True) -> str: start, end = string.index('{') + 1, string.index('}') replace_str = string[start: end] var_replace = replace_str.split('||') string = string.replace(replace_str, '') # Можно схитрить, т.к. True -- 1, False -- 0 # return string.format(var_replace[not s]) return string.format(var_replace[0] if s else var_replace[1]) string = "words{hello||hello1}words" print(foo(string, True)) # wordshellowords print(foo(string, False)) # wordshello1words Вариант через регулярку: import re def foo(string: str, s=True) -> str: def _on_match(match): var_replace = match.group()[1:-1].split('||') return var_replace[0] if s else var_replace[1] return re.sub('{.+?}', _on_match, string) string = "words{hello||hello1}words" print(foo(string, True)) # wordshellowords print(foo(string, False)) # wordshello1words

Ответ 2



Чтобы выбрать при замене в шаблоне первую альтернативу, когда first=True: import re format_spec = "words{AAA||BBB}words" first = True print(re.sub( "{([^}]+)}", lambda match: match.group(1).split("||")[not first], format_spec, )) Результат: wordsAAAwords Здесь используется, что True == 1, а False == 0, поэтому булевы переменные могут использоваться в качестве индексов. К примеру, [1, 2][True] возвращает 2, а [1, 2][False] возвращает 1.

Ответ 3



string = "wordshello{}words" s = True print(string.format(int(s) or '')) # 'wordshello1words' s = False print(string.format(int(s) or '')) # 'wordshellowords'

Ответ 4



string = 'words{}words' subs = ['hello1', 'hello'] s = True print(string.format(subs[s])) # wordshellowords Трюк в том, что при преобразовании в целое число True станет 1, а False – 0, и таким образом выбираем элемент по индексу.

Ответ 5



import re string = 'words{hello||hello1}words' parts = re.split(r'[{|}]', string) if s == True: print(parts[0] + parts[1] + parts[-1]) else: print(parts[0] + parts[-2] + parts[-1])

Вернуть индекс элемента списка, зная часть его значения

#python #list


Например, есть список:

['Город Москва', 'Город Киев', 'Город Харьков', 'Город Краснодар']


Как вернуть индекс элемента зная его значение? Например Харьков.
    


Ответы

Ответ 1



In [33]: items Out[33]: ['Город Москва', 'Город Киев', 'Город Харьков', 'Город Краснодар'] решение "в лоб": In [34]: [i for i,x in enumerate(items) if 'Харьков' in x][0] Out[34]: 2

Ответ 2



lst = ['Город Москва', 'Город Киев', 'Город Харьков', 'Город Краснодар'] pattern = 'Харьков' # Чтобы остановиться на первом совпадении for i in range(len(lst)): if pattern in lst[i]: print(i) break # Чтобы получить все индексы где есть паттерн print(*[i for i in range(len(lst)) if pattern in lst[i]])

Ответ 3



Я тоже сражусь за оригинальность: list = ['Город Москва', 'Город Киев', 'Город Харьков', 'Город Краснодар'] for index, elem in enumerate(list): if (elem.find('Харьк')!= -1): print(index) break

Ответ 4



list=['Город Москва', 'Город Киев', 'Город Харьков', 'Город Краснодар'] i=-1 for elem in list: i+=1 if elem==('Город Харьков'): break print(i)

Ответ 5



Просто примените метод index(): In[2]: lst = ['Город Москва', 'Город Киев', 'Город Харьков', 'Город Краснодар'] In[3]: lst.index('Город Харьков') Out[3]: 2

Исключение std::bad_alloc для 2 элементов

#cpp #исключения #gcc


Почему следующая программа выбрасывает исключение std::bad_alloc?

int main() {
    std::vector delimiters = {",", ";"};
    std::cout << delimiters[0];
}

    


Ответы

Ответ 1



У Вас очень занятный пример получился. Вот в этой строчке: std::vector delimiters = {",", ";"}; происходит попытка создать вектор из двух итераторов, т.к. это единственный подходящий конструктор, который компилятору удаётся распознать в этой инициализации: {",", ";"}. Т.к. компилятор считает, что ему дают 2 итератора, то он и пытается с ними работать, но на деле это 2 независимых указателя, работа с которыми даёт неопределённое поведение! Вот поэтому Вы и видите исключение. Компилятор, скорее всего, честно вычел из второго указателя первый, получил какое-то огромное число, попытался выделить и получил std::bad_alloc.

Ответ 2



Потому что вы говорите о char, а передаете строки... std::vector delimiters = {',', ';'};

Чем отличается хранение в памяти массивов из величин значимого и ссылочного типа?

#c_sharp #массивы #память #типы #c_sharp_faq


Чем отличается хранение в памяти массивов из величин значимого и ссылочного типа?
    


Ответы

Ответ 1



Массив - это непрерывная область памяти, в которой последовательно, друг за другом, размещены некоторые элементы. У массива есть заголовок, о котором, обычно, никто не говорит (и не знает), и собственно значения. Если речь о значимых типах (структурах), они размещаются непосредственно в области выделенной для массива. В случае ссылочных типов (классов), их экземпляры размещаются в куче, а массив содержит всё те же структуры (IntPtr) - указатели на эти объекты. В отличии от массива значимых типов, массив ссылочных типом может содержать элементы указывающие на один и тот же объект.

Ответ 2



Если отвлечься от специфики именно массивов C# (которые являются ссылочными), то переменная значимого типа хранит непосредственно значение, а переменная ссылочного типа хранит адрес значения. Само значение при этом хранится в динамической памяти (куче).

Ответ 3



Все массивы являются ссылочными типами. Arrays are mechanisms that allow you to treat several items as a single collection. The Microsoft® .NET Common Language Runtime (CLR) supports single-dimensional arrays, multidimensional arrays, and jagged arrays (arrays of arrays). All array types are implicitly derived from System.Array, which itself is derived from System.Object. This means that all arrays are always reference types which are allocated on the managed heap, and your app's variable contains a reference to the array and not the array itself. https://stackoverflow.com/questions/1533757/is-int-a-reference-type-or-a-value-type https://docs.microsoft.com/en-us/previous-versions/dotnet/articles/bb985948(v=msdn.10)

Вопрос про специализацию и шаблонны классы со статическими данными

#cpp #cpp11 #шаблоны_с++


допустим есть шаблонный класс: 

template
class X
{
public:
    static T t;
    static T foo()
    {
        return t;
    }
};


В чём разница между такой инициализацией статического члена t

double X::t = 5.0f;


и такой инициализацией со специализацией класса (или статического члена !?) ?

template<>
double X::t = 5.0f;

    


Ответы

Ответ 1



Оба синтаксиса формально корректны, но первый не применим в данном контексте. У вас есть возможность использовать четыре относительно "похожих" синтаксиса за пределами определения самого шаблонного класса // 1 template T X::t; // "Общее" определение статического члена. // Является определением независимо от наличия инициализатора. // 2 template<> double X::t = 3; // Явная специализация статического члена для `T == double`. // Является определением только при наличии инициализатора. Без инициализатора // является просто объявлением. // Определения, предоставленные методом 1, не распространяются на явные // специализации, т.е. определение для явной специализации требуется // предоставить отдельно. // 3 template double X::t; // Явное инстанцирование статического члена для `T == double`. // Не допускает указания инициализатора. // Может выполняться только после выполнения определения или явной // специализации. В последнем случае - не имеет никакого эффекта. // 4 double X::t = 3; // Определение статического члена явной специализации. // Является определением независимо от наличия инициализатора. // Требует, чтобы явная специализация шаблона класса была определена выше. Все эти синтаксические конструкции единообразно распространяются и на объявления методов класса. В данном случае, однако, мы говорим именно о статических данных. Таким образом ваше первое объявление будет являться корректным в том и только в том случае, если оно следует за определением явной специализации шаблона класса X для T == double template class X { public: static T t; }; template<> class X { public: static double t; }; double X::t = 5.0f; Но без явной специализации шаблона класса, как в вашем конкретном примере, такое объявление неуместно.

Ответ 2



Да, разница существенна, запись double X::t = 5.0f; является невалидной и вызовет ошибку компиляции.

Указатель на функцию и производительность

#cpp


void foo(){}
//...
void (*fptr)() = foo;


Влияет ли использование указателя на функцию на производительность? (как?)
    


Ответы

Ответ 1



Одиночный вызов через указатель может негативно влиять на производительность просто потому, что целевой адрес необходимо читать из памяти данных, т.е. он не содержится непосредственно в потоке команд. Одиночный вызов через указатель может негативно влиять на производительность потому, что косвенная передача управления затрудняет предсказание переходов и поэтому может подавлять конвейерную обработку команд в современных суперскалярных процессорах. Если конкретная машинная архитектура не занимается предсказанием переходов и суперскалярной обработкой команд, то этот недостаток на таких архитектурах не будет иметь места. Множественный вызов через указатель на один и тот же адрес (напр. в цикле) может НЕ привести к ухудшению производительности потому, что чтение целевого адреса из памяти (в регистр процессора) может быть выполнено один раз заранее (пункт 1) и тривиальный подход к предсказанию косвенных переходов дает правильный результат (пункт 2). Разумеется, предварительное "кэширование" целевого адреса на уровне сгенерированного компилятором кода возможно только в том случае, если компилятор уверен в том, что адрес остается неизменным от вызова к вызову.

Ответ 2



Здесь скорее более уместно говорить о том будет ли сгенерирован одинаковый машинный код для прямого вызова функции и вызова функции по указателю. И, если машинный код будет одинаковый, то и производительность никак не изменится вне зависимости от архитектуры процессора. В данном случае за все отвечает транслятор языка. И, конечно, без оптимизации скорее всего вызов по указателю будет содержать дополнительное действие. Но, при малейшей оптимизации, эти вызовы уже станут одинаковыми. Мало того, при небольшом объеме функции ее тело вообще может быть вставлено в код. В конечном итоге сложно сказать какой код сгенерирует транслятор языка, все зависит от самого транслятора и его опций оптимизации. Но практика показывает, что большинство трансляторов, даже довольно давних, хорошо оптимизирует код. Например следующий код (gcc 8.2 -O3): int main() { int (*f)() = func; func(); f(); return 0; } будет транслирован в: main: sub rsp, 8 call func() call func() xor eax, eax add rsp, 8 ret Как видно вызов функций одинаков. Можете перейти по ссылке выше и поэксперементировать с разными компиляторами и опциями оптимизации. А, отвечая на вопрос, то, при даже небольшой оптимизации, подавляющее большинство трансляторов сгенерируют код при котором использование указателя на функцию никак не повлияет на производительность.

Z-индекс изображения при наведении на несколько SVG полигонов

#html #css #svg #css_animation


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

Моя цель - добиться первого наложения части фигуры от полного отображения изображения
 при наведении курсора на фон фигуры.  Границы  многоугольника также должны быть видны.  

Это мой исходный код перед наложением изображения:



.box {
  position: relative;
  background-image: url('https://picsum.photos/id/1/1000/800');
  background-repeat: no-repeat;
  width: 100%;
  height: 600px;
  background-size: cover;
}

polygon {
  stroke-width: 1;
  stroke: red;
  fill: #ffffff;
}

polygon:hover {
  fill: transparent;
}
Теперь я добавил overlay изображение, которое должно располагаться над изображением .box и многоугольниками. Теперь, при наведении курсора, я хочу отобразить .box изображение в текущей форме многоугольника, как это код здесь: .box { position: relative; background-image: url('https://picsum.photos/id/1/1000/800'); background-repeat: no-repeat; width: 100%; height: 600px; background-size: cover; } polygon { stroke-width: 1; stroke: red; fill: #ffffff; } polygon:hover { fill: transparent; } .overlay:hover polygon { z-index: 100; } .overlay { position: absolute; background-image: url('https://picsum.photos/id/118/1000/800'); background-repeat: no-repeat; width: 100%; height: 600px; background-size: cover; z-index: 10; }
Может ли кто-нибудь помочь мне с этим при наведении курсора. Нужно отрегулировать z-индексы div и заполнения полигонов.


Ответы

Ответ 1



rect, polygon { stroke-width: 0; fill: none; pointer-events: all; } rect, polygon:hover { fill: url(#f); } Если нижняя часть изображения не нужна, то так: svg { overflow: hidden; } polygon { stroke-width: 0; stroke: transparent; fill: none; pointer-events: all; } polygon:hover { fill: url(#f); }

Ответ 2



Я скорректировал код моего предыдущего ответа, как показано ниже: .box { width:450px; height:250px; position:relative; overflow:hidden; z-index:0; background:url(https://picsum.photos/id/13/1000/800) center/cover; } .box > div { position:absolute; top:0; left:0; right:0; bottom:0; background-size:cover; background-position:center; opacity:0; } .box > div:nth-child(1) { clip-path:polygon(20% 0,80% 0, 50% 100%); } .box > div:nth-child(2) { clip-path:polygon(0 0, 20% 0,50% 100%,0 40%); } .box > div:nth-child(3) { clip-path:polygon(100% 0,80% 0,50% 100%,100% 40%); } .box > div:nth-child(4) { clip-path:polygon(0 100%,50% 100%,0 40%); } .box > div:nth-child(5) { clip-path:polygon(100% 100%,50% 100%,100% 40%); } .box > div:hover { opacity:1; }
Вот иллюстрация, чтобы показать вам различные точки, используемые в пути клипа С тем же изображением? как у автора: .box { width:450px; height:250px; position:relative; overflow:hidden; z-index:0; background:url(https://picsum.photos/id/13/1000/800) center/cover; } .box > div { position:absolute; top:0; left:0; right:0; bottom:0; background-image:url(https://picsum.photos/id/118/1000/800); background-size:cover; background-position:center; opacity:0; } .box > div:nth-child(1) { clip-path:polygon(20% 0,80% 0, 50% 100%); } .box > div:nth-child(2) { clip-path:polygon(0 0, 20% 0,50% 100%,0 40%); } .box > div:nth-child(3) { clip-path:polygon(100% 0,80% 0,50% 100%,100% 40%); } .box > div:nth-child(4) { clip-path:polygon(0 100%,50% 100%,0 40%); } .box > div:nth-child(5) { clip-path:polygon(100% 100%,50% 100%,100% 40%); } .box > div:hover { opacity:1; }
Источник ответа: @Temani Afif

Ответ 3



Решение @Temani Afif только на CSS очень хорошее Однако, будьте осторожны, это все еще не поддерживается ни в Safari, ни в IE / Edge. Для этих браузеров вам понадобится использовать SVG, который также реализует элемент . .overlay { background-image: url('https://picsum.photos/id/118/1000/800'); background-repeat: no-repeat; background-size: cover; } .overlay use { opacity: 0; } .overlay use:hover { opacity: 1; }
Так что, это более многострочно в коде, но это должно работать в любом браузере начиная с IE9. Источник ответа: @Kaiido

Код-ревью: разделение файлов в каталоге по типу контента

#c_sharp #winforms #инспекция_кода #preview


Пишу для себя программу, которая разгребает каталог(например: рабочий стол) и раскидывает
файлы по каждому формату в заданный пользователем каталог (например: jpg кидает в папку
"Изображения", mp3 в папку "музыка", zip и rar в каталог архивы и т.д.). 
Программа работает, для полного завершения осталось написать сервис чтобы работала
автономно (например как антивирус). Но для того чтобы приступить к разработке сервиса,
хочу попросить Вас сделать код-ревью, т.к. показать, к сожалению, некому. Все коллеги
разрабатывают ETL и далеки от данной тематике. 
Буду Вам очень признателен, т.к. очень хочу быть профессиональным разработчиком.

Класс, где хранятся все параметры:

namespace Transporter
{
public class Data
{
    public Data()
    {
        string fileName = settingsFile;

        if (File.Exists(fileName) && !File.ReadAllText(fileName).Equals("") && File.ReadAllText(fileName)
!= null)
        {
                XElement xElem2 = XElement.Load(fileName);
                formats =  xElem2.Descendants("item")
                                    .ToDictionary(x => (string)x.Attribute("format"),
x => (string)x.Attribute("path"));   
        }
        else
        {
            formats = new Dictionary();
        } 
    }

    private static string settingsFile = "settings.xml";

    private readonly Dictionary formats;
    public Dictionary Formats
    {
        get { return formats; }
    }
    private string path = null;
    public string Path
    {
        get { return path; }
        set { path = value; }
    }

    public void Add(string format, string path)
    {
        if (!formats.ContainsKey(format))
            formats.Add(format, path);
        else
        {
            formats.Remove(format);
            formats.Add(format, path);
        }
    }

    public void Save()
    {
        string fileName = settingsFile;

        if (File.Exists(fileName)) File.Delete(fileName);

        using (FileStream fileStream = new FileStream(fileName, FileMode.Create))
        {
            XElement xElem = new XElement
            (
             "items",
             formats.Select(x => new XElement("item", new XAttribute("format", x.Key),
new XAttribute("path", x.Value)))
            );
            xElem.Save(fileStream);
            fileStream.Close();
        }
    }

    public void RemoveSettingsFile()
    {
        if (File.Exists(settingsFile)) File.Delete(settingsFile);
    }
}

public class item
{
    [XmlAttribute]
    public string path;
    [XmlAttribute]
    public string format;
}

}


Класс, который обрабатывает параметры класса Data:

namespace Transporter
{
class Handler
{
    private Data data = new Data();
    public void AddFormat(string format,string path)
    {
        data.Add(format, path);
    }

    public void AddPath(string path)
    {
        data.Path = path;
    }

    public void DelAllFormats()
    {
        data.Formats.Clear();
        data.RemoveSettingsFile();
    }

    public string GetParameters()
    {
        StringBuilder builder = new StringBuilder();
        builder.AppendLine("Исходный каталог:");
        builder.AppendLine(data.Path == null ? "исходный каталог не указан" : data.Path);
        builder.AppendLine();

        builder.AppendLine("Форматы файлов и каталоги, куда файлы будут перенесены:");
        if (data.Formats.Count == 0)
            builder.AppendLine("Форматы файлов и каталоги не указаны");
        else
        {
            foreach (var format in data.Formats)
            {
                builder.AppendLine(string.Format("{0} => {1}", format.Key, format.Value));
            }
        }
        return builder.ToString();
    }

    public void MoveFiles(CancellationToken token)
    {
        while (!token.IsCancellationRequested)
        {
            try
            {
                var files = Directory.GetFiles(data.Path);
                foreach (string file in files)
                {
                    foreach (var format in data.Formats)
                    {
                        var fileInfo = new FileInfo(file);
                        if (fileInfo.Extension.ToLower().Contains(format.Key.ToLower()))
                        {
                            fileInfo.MoveTo(format.Value + @"\" + DateTime.Now.ToString("yyyyMMdd_hhmmss_")
+ fileInfo.Name);
                        }
                    }
                }
                Thread.Sleep(5000);
            }
            catch (IOException) { }
            catch (KeyNotFoundException) { }
        }
    }

    public void SaveSetting()
    {
        data.Save();
    }

    public bool checkParametrsForStart()
    {
        return data.Path != null && data.Formats.Count > 0;
    }
}
}


Форма:

namespace Transporter
{

public partial class Transporter : Form
{
    private Handler handler = new Handler();
    private CancellationTokenSource cancellationTokenSource;

    public Transporter()
    {
        InitializeComponent();

        StringBuilder builder = new StringBuilder();
        builder.AppendLine("Для начала работы укажите:");
        builder.AppendLine("1) исходный каталог - откуда бы Вы хотели перенести файлы;");
        builder.AppendLine("2) форматы файлов с каталогами - куда бы Вы xотели переместить
файлы.");
        builder.AppendLine();
        builder.AppendLine("Кнопка 'Start' запускает перенос файлов.");
        builder.AppendLine("Кнопка 'Stop' останавливает перенос файлов.");
        builder.AppendLine("Кнопки 'Add' добавлют параметры.");
        builder.AppendLine("Кнопка 'Reset' сбрасывает параметры переноса.");
        builder.AppendLine("Кнопка 'View' выводит текущие параметры в консоль.");
        builder.AppendLine("Кнопка 'Clear' очищает консоль.");
        builder.AppendLine("Кнопка 'Save' сохраняет текущие параметры.");
        builder.AppendLine();
        builder.AppendLine("Автор программы: Rumeet94 (https://vk.com/evgengorb)");

        tbMessage.Text = builder.ToString();
    }

    private void BtnAddDiir_Click(object sender, System.EventArgs e)
    {
        if (Regex.IsMatch(tbDir.Text, @"^.:\w*", RegexOptions.IgnoreCase))
        {
            handler.AddPath(tbDir.Text);
            tbMessage.Text = "Путь исходного каталога успешно добавлен";
        }
        else
        {
            tbMessage.Text = "Путь исходного каталога указан некорректно";
        }
    }

    private void BtnAddFormatAndDir_Click(object sender, System.EventArgs e)
    {
        if (Regex.IsMatch(tbFormatDir.Text, @"^.:\w*", RegexOptions.IgnoreCase) &&
!tbFormat.Text.Equals(""))
        {
            handler.AddFormat(tbFormat.Text, tbFormatDir.Text);
            tbMessage.Text = "Формат и путь каталога для переноса файлов успешно
добавлены";
        }
        else
        {
            tbMessage.Text = "Не указан формат или путь каталога для переноса файлов
указан некорректно";
        }

    }


    private void BtnStop_Click(object sender, System.EventArgs e)
    {
        tbMessage.Text = "Перенос файлов остановлен.";
        cancellationTokenSource?.Cancel();

        tbDir.ReadOnly = false;
        tbFormat.ReadOnly = false;
        tbFormatDir.ReadOnly = false;

        btnStart.Enabled = true;
        btnAddDiir.Enabled = true;
        btnAddFormatAndDir.Enabled = true;
        btnResPar.Enabled = true;
    }

    private void BtnStart_Click(object sender, System.EventArgs e)
    {
        if (handler.checkParametrsForStart()) {
            tbDir.ReadOnly = true;
            tbFormat.ReadOnly = true;
            tbFormatDir.ReadOnly = true;

            btnStart.Enabled = false;
            btnAddDiir.Enabled = false;
            btnAddFormatAndDir.Enabled = false;
            btnResPar.Enabled = false;

            cancellationTokenSource = new CancellationTokenSource();

            tbMessage.Text = "Выполняется перенос файлов";
            Task.Run(() => handler.MoveFiles(cancellationTokenSource.Token));
        }
        else
        {
            tbMessage.Text = "Невозможно запустить перенос файлов, т.к. исходный
каталог " +
                "или форматы и каталоги для переноса файлов не указаны";
        }
    }

    private void BtnViewPar_Click(object sender, System.EventArgs e)
    {
        tbMessage.Text = handler.GetParameters();
    }

    private void BtnResPar_Click(object sender, System.EventArgs e)
    {
        handler.DelAllFormats();
    }

    private void BtnClearCon_Click(object sender, System.EventArgs e)
    {
        tbMessage.Text = "";
    }

    private void BtnSave_Click(object sender, System.EventArgs e)
    {
        handler.SaveSetting();
    }
}
}

    


Ответы

Ответ 1



Из того, что мне сразу бросилось в глаза: Класс, где хранятся все параметры. Можно было работать с app.config и использовать штатные возможности, предоставляемые языком. Вместо этого используется кастомный XML файл. Почему бы не начать хотя бы ConfigurationManager.AppSettings["SettingsName"]? Что-то стояло за этим выбором? Метод GetParameters в классе Handler одновременно читает настройки (должно быть: Init в Settings?), валидирует (ValidateConfig) и форматирует текст сообщения об ошибках. Пустые catch без объяснения -- нехорошо: catch (IOException) { } catch (KeyNotFoundException) { } В конструкторе Transporter можно выделить отдельный метод: StringBuilder builder = new StringBuilder(); builder.AppendLine("Для начала работы укажите:"); builder.AppendLine("1) исходный каталог - откуда бы Вы хотели перенести файлы;"); builder.AppendLine("2) форматы файлов с каталогами - куда бы Вы xотели переместить файлы."); builder.AppendLine(); builder.AppendLine("Кнопка 'Start' запускает перенос файлов."); builder.AppendLine("Кнопка 'Stop' останавливает перенос файлов."); builder.AppendLine("Кнопки 'Add' добавлют параметры."); builder.AppendLine("Кнопка 'Reset' сбрасывает параметры переноса."); builder.AppendLine("Кнопка 'View' выводит текущие параметры в консоль."); builder.AppendLine("Кнопка 'Clear' очищает консоль."); builder.AppendLine("Кнопка 'Save' сохраняет текущие параметры."); builder.AppendLine(); builder.AppendLine("Автор программы: Rumeet94 (https://vk.com/evgengorb)"); tbMessage.Text = builder.ToString(); Сразу будет понятно, что конструктор делает два действия (InitializeComponent и GetTextForAboutButton), кому нужны детали как выглядит этот метод -- кликнет и перейдёт. Кстати, я не вижу никакого обоснования зачем вам понадобился string builder -- у вас же константа: const string About = @"Для начала работы укажите: 1) исходный каталог - откуда бы Вы хотели перенести файлы; 2) форматы файлов с каталогами - куда бы Вы xотели переместить файлы. Кнопка 'Start' запускает перенос файлов. Кнопка 'Stop' останавливает перенос файлов. Кнопки 'Add' добавлют параметры. Кнопка 'Reset' сбрасывает параметры переноса. Кнопка 'View' выводит текущие параметры в консоль. Кнопка 'Clear' очищает консоль. Кнопка 'Save' сохраняет текущие параметры. Автор программы: Rumeet94 (https://vk.com/evgengorb)"; Это конечно здорово, что вас научили пользоваться StringBuilder для конкатенации строк, но тут пока оверхед: не надо каждый раз при запуске программы вычислять эту строку, достаточно один раз при компиляции ПО. Здесь напрашивается функция с говорящим именем IsDirectoryNameValid(tbDir.Text): if (Regex.IsMatch(tbDir.Text, @"^.:\w*", RegexOptions.IgnoreCase)) { handler.AddPath(tbDir.Text); tbMessage.Text = "Путь исходного каталога успешно добавлен"; } else { tbMessage.Text = "Путь исходного каталога указан некорректно"; } И уже внутри деталь реализации, что это делается регулярками. Вот это -- некоторая магическая константа: Thread.Sleep(5000); Нужно ей дать имя, хотя бы TaskDelayBetweenFiles и сделать для начала хотя бы константой класса (хотя лучше сразу в конфиг-файл вынести!), а кроме того, хорошо бы придумать такое имя, из которого было бы сразу стало понятно, зачем нужна эта задержка. Сейчас вот -- непонятно. Вот тут решарпер обычно выдаёт что можно сделать readonly: private Handler handler = new Handler(); private CancellationTokenSource cancellationTokenSource; private Data data = new Data(); И у вас в некоторых местах так сделано. Вот тут .Close() не нужен: using (FileStream fileStream = new FileStream(fileName, FileMode.Create)) { ... fileStream.Close(); } Попробуйте просто кликнуть по Close и посмотреть, как выглядят исходники этого метода: /// Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. Instead of calling this method, ensure that the stream is properly disposed. public virtual void Close() { this.Dispose(true); GC.SuppressFinalize((object) this); } /// Releases all resources used by the . [__DynamicallyInvokable] public void Dispose() { this.Close(); } У вас блок using который автоматически вызовет .Dispose() и из него - .Close(). Вот это одна из самых типовых ошибок новичков, которые просто не видят в упор эти пустые строки: private void BtnAddFormatAndDir_Click(object sender, System.EventArgs e) { if (Regex.IsMatch(tbFormatDir.Text, @"^.:\w*", RegexOptions.IgnoreCase) && !tbFormat.Text.Equals("")) { handler.AddFormat(tbFormat.Text, tbFormatDir.Text); tbMessage.Text = "Формат и путь каталога для переноса файлов успешно добавлены"; } else { tbMessage.Text = "Не указан формат или путь каталога для переноса файлов указан некорректно"; } } (посмотрите внимательно между двумя последними фигурными скобками) Таких мест у вас несколько, вы их визуально не считываете. Посмотрите например в конец класса и обратите внимание на пустую строку между фигурной скобкой класса и фигурной скобкой последнего метода. А, показалось: у вас там вообще конец класса и неймспейса. Также вы ставите порой две пустых строки между методами - а зачем? Ставьте одну: } private void BtnStop_Click(object sender, System.EventArgs e) { Ещё в тему отступов: у вас нет отступа внутрь Namespace: namespace Transporter { public class Data И вероятно, лучше настроить assembly name чтобы неймспейс был CompanyName.ProjectName или ProjectName хотя бы. private void BtnStop_Click(object sender, System.EventArgs e) { Вот тут не хватает фигурных скобок в if: if (!formats.ContainsKey(format)) formats.Add(format, path); else { formats.Remove(format); formats.Add(format, path); } if (File.Exists(settingsFile)) File.Delete(settingsFile); Да, они необязательны. И тут надо чётко понимать, что лучше их поставить сразу. Такие вещи должны быть зафиксированы в любом виде в кодстайле, чтобы не было пустых споров "а мне так нравится" и все писали единообразно, даже если этот пишете якобы только вы один. (Якобы -- потому что через полгода читать код будете не "я текущий", а "я через полгода", это совсем разные люди) Вот мне лично тоже больше нравится опускать эти скобки, но в большинстве кодстайлов я видел зафиксированной их обязательность. Из плюсов: чище будет diff если вы когда-нибудь вынуждены будете добавить что-то там: при расставленных фигурных скобках будет просто одна строка добавлена. Вот эти две портянки кода нужно убрать в метод DisableButtons и EnableButtons: btnStart.Enabled = true; btnAddDiir.Enabled = true; btnAddFormatAndDir.Enabled = true; btnResPar.Enabled = true; tbDir.ReadOnly = true; tbFormat.ReadOnly = true; tbFormatDir.ReadOnly = true; btnStart.Enabled = false; btnAddDiir.Enabled = false; btnAddFormatAndDir.Enabled = false; btnResPar.Enabled = false; И ваш код сразу станет чище и понятнее, а также не нужно будет его постоянно в разных местах так подробно расписывать. Почему имя класса с маленькой буквы? public class item И сюда же: formats.Select(x => new XElement("item", new XAttribute("format", x.Key) Зачем вы захардкодили строки? Меняем их на nameof(item) и nameof(item.format).

Ответ 2



Предупреждаю сразу, что я не профессиональный инспектор кода, но знаком с некоторыми рекомендациями по разработке приложений с публичным API под .NET, их и некоторые другие опишу ниже. private static string settingsFile = "settings.xml"; Возможно, стоило добавить модификатор readonly или вообще вынести в константу через const. private readonly Dictionary formats; public Dictionary Formats { get { return formats; } } Вместо класса Dictionary как тип свойства стоит использовать интерфейс IDictionary, потому что нужно стараться уходить от конкретных реализаций к интерфейсам, когда это возможно. private string path = null; public string Path { get { return path; } set { path = value; } } Имеет смысл заменить на автосвойство, потому что у вас нет никакой дополнительной логики ни в геттере, ни в сеттере, но это больше дело вкуса, чем рекомендация. public class item { [XmlAttribute] public string path; [XmlAttribute] public string format; } Публичные классы и публичные члены классов должны называться в PascalCase, т.е. стоило бы переименовать класс в Item, а поля в Path и Format. Еще лучше было бы сделать поля свойствами, потому что если бы вы вдруг отправили API пользователям с публичными полями, а потом решили бы поменять их на свойства, вы не смогли бы сделать это без потери обратной совместимости с прошлыми версиями. Несмотря на то, что члены бы имели те же самые имена, пользовательские приложения не смогли бы работать с вашей библиотекой без повторной компиляции, потому что поля и свойства для CLR - не одно и то же. Кржиштоф Цвалина, Брэд Абрамс - Инфраструктура программных проектов (Microsoft .NET Development) Хорошая книга, в которой описаны особенности разработки публичных API на CLR-совместимых языках.

Ответ 3



Коллеги указали на часть ошибок, но есть и другие. Опишу их. Конструктор класса Data. if (File.Exists(fileName) && !File.ReadAllText(fileName).Equals("") && File.ReadAllText(fileName) != null) Проверка File.Exists не гарантирует, что файл окажется на месте. Он может быть удалён уже после проверки, но раньше доступа к нему. Поэтому желательно обернуть код в try-catch с перехватом исключений. Возможны FileNotFoundException, теоретически UnauthorizedAccessException... Чтение одного и того же файла выполняется дважды. Это дорогая и медленная операция. Проверка на null выполняется последней. Следовательно, при вызове .Equals можно было бы словить NullReferenceException, если бы ReadAllText вернул null. Потом файл читается в третий раз при вызове XElement.Load(fileName). Ужас! И если там будет невалидный xml - опять возможны исключения. Странные действия в методе Add в ветке else. Достаточно: formats[format] = path; Метод Save. Необязательно удалять файл, т. к. перегрузка new FileStream(fileName, FileMode.Create), по сути, сама это сделает благодаря FileMode.Create. В надёжном софте (а ваш сервис, как я понимаю, будет работать постоянно) все операции ввода-вывода должны позаботиться об обработке исключений. Диск в любой момент может сбойнуть, на нём может закончиться место и т. п. Атрибуты [XmlAttribute] нужны только для xml-сериализации. Вы не используете XmlSerializer, а делаете парсинг и составление xml вручную. Следовательно, эти атрибуты не нужны. Посмотрим класс Handler. Метод GetParameters. Я сторонник лаконичности. Переписал бы начало так: var builder = new StringBuilder() .AppendLine("Исходный каталог:") .AppendLine(data.Path ?? "исходный каталог не указан") .AppendLine() .AppendLine("Форматы файлов и каталоги, куда файлы будут перенесены:"); В цикле foreach, вместо жутко неэффективного string.Format, написал бы так: builder.Append(format.Key).Append(" => ").AppendLine(format.Value); Конечно, это такая оптимизация, что и в микроскоп не разглядишь, но раз уж мы используем StringBuilder, то нужно использовать его по полной. Переходим к форме. В её конструкторе используется StringBuilder для собирания в одно целое строковых литералов, которые известны заранее, на этапе компиляции. Можно выбросить этот билдер и просто написать одну большую строку. Если хочется красивого форматирования, то можно так: string text = "Для начала работы укажите:" + Environment.NewLine + "1) исходный каталог - откуда бы Вы хотели перенести файлы;" + Environment.NewLine + ... Т. к. это литералы, то они будут склеены в одну строку на этапе компиляции. В рантайме конкатенации не будет. Для большей краткости можно использовать "\r\n". Отмечу положительно отключение/включение контролов (Enabled/ReadOnly) перед началом работы, после её завершения. Защита от дурака - не дать пользователю выполнить запрещённое действие - лучше всего. Task.Run(() => handler.MoveFiles(cancellationTokenSource.Token)); Кхгм... Знаю, что это именно я так написал... Но в данном конкретном случае это не очень хороший код. Метод Task.Run, запуская задачу, берёт поток из пула. Пул должен использоваться только для коротких задач. Взяли поток, что-то быстро сделали, вернули поток в пул. А у вас задача выполняется долго, возможно даже всегда. Для такой цели лучше создать отдельный поток, не из пула. Task.Factory.StartNew(() => handler.MoveFiles(cancellationTokenSource.Token), TaskCreationOptions.LongRunning); LongRunning означает, что задача долгоиграющая и для неё будет создан отдельный поток.

Как посчитать количество элементов ul в JavaScript?

#javascript


Хочу сделать меню в две строки, для этого мне нужно посчитать количество элементов
ul, какая функция в javascript отвечает за это?
Пробовал примерно так:
  • Главная
  • Контакты
  • Резюме
  • Портфолио
  • Услуги
  • Стихи
  • Программы
  • Статьи
Скрипт должен считать количество li и после каждой 4-ой, переводить остальные на следующую строку.


Ответы

Ответ 1



Как минимум есть два способа
  • aaaa
  • bbbb
  • ......


Ответ 2



Этот код не валидный DOM, нужно использовать dom-функции: document.getElementsByTagName('ul')[0].getElementsByTagName('li'); Но именно Ваша задача решается так:
  • element 1
  • element 2
  • element 3
  • element 4
  • element 5
  • element 6


Ответ 3



или так: var len = document.querySelector('ul').children.length;

Получить список таблиц в пользовательских БД в SQL Server

#sql_server #sql


Добрый день. Подскажите запрос на получение списка таблиц пользовательских (не системных)
баз данных в SQL Server 2008.    


Ответы

Ответ 1



//Выдает все базы данных на сервере SELECT name FROM sys.databases //Выдает все таблицы в Базе данных SELECT * FROM sys.objects WHERE type in (N'U')

Ответ 2



Есть ещё вариант SELECT * FROM INFORMATION_SCHEMA.TABLES Он более кроссплатформенный относительно СУБД, т.к. INFORMATION_SCHEMA является частью стандарта SQL, а sys.objects нет. Хотя там есть не всё, многие вещи без представлений из схемы sys не получить.

Какие шаблоны лучше использовать в многоцелевой CMS?

#php #cms #html


Доброго всем дня!
Интересует мнение большинства, какие шаблоны лучше использовать в многоцелевой CMS?
Что лучше: php+html, smarty, twig...?
Хотелось бы получить максимум отзывов (без "религиозных" споров) просто по делу,
нравится ... потому что ...
Заранее спасибо!    


Ответы

Ответ 1



Многое зависит от того, какие требований к шаблонизатору. Так например, одни шаблонизаторы могут быть более гибкими, вторые более быстрыми, третьи лучше отделяют логику от представления. Из тех шаблонизаторов, с которыми мне приходилось работать самому, я бы мог выделить следующие: Шаблоны на "чистом" php, будем называть их php mess. Возможности. Тут все понятно. Все есть в вашем проекте, доступно и здесь "из коробки". Скорость. Так же очевидно, что скорость будет ограничиваться разве что кривизной шаблонов. Расширяемость. См. возможности. Юзабилити. А вот это пункт сводит на нет все преимущества предыдущих пунктов. Нет никакой разделяемости логики от представлений. Конструкции типа
$val) : ?php>
как правило неизбежны и быстро превращают шаблон в жутчайшее месиво говнокода. Отсутствие каких-либо песочниц или ограничений на выполняемый код делают его настоящим генератором багов. Крайне не рекомендовал бы использовать этот подход ни в каких проектах сложнее Hello, World. Smarty - старейший и хорошо всем известный шаблонизатор. Возможности. Имеются функции, модификаторы, ветвления, инклюды. Компилирует шаблоны в php mess. В общем, стандартный набор шаблонизатора. Ничего особо примечательного нету. Песочницы нету. Скорость. Написан на PHP, шаблоны компилирует в php mess. Но из-за большего overhead на обслуживание и выполнение шаблонов, достаточно медлителен. Хотя, начиная с версии 3 стал пошустрее, но все равно достаточно далек от идеала. Расширяемость. Можно создавать свои функции и модификаторы, которые будут выполняться в runtime. Собственно, все. Юзабилити. Хорошая документация. Синтаксис, на мой взгляд, хоть и не очень лаконичен, но понятен любому грамотному верстальщику. Однако, наличие тега '{php}' и бесконтрольное добавление функций может легко превратить шаблон в месиво, похлеще чем встречается в php mess. Интегрируется со многими IDE. Рекомендовал бы его только в случае, когда есть верстальщики уже работавшие с ним и не желающие что-либо переучивать. Twig - новомодный шаблонизатор. Во многом схож с питоновским шаблонизатором Django. Возможности. В чем-то схожи со Smarty. Те же модификаторы, циклы, ветвления, инкюды (но, к счастью, нету тега {php} или аналогов). Помимо этого предоставляет возможности блочной шаблонизации, наследование шаблонов, макросы и прочие мелкие полезности. Так же есть возможность настраивать лексемы языковых конструкций, что может упростить миграцию шаблонов других шаблонизаторов. Имеется песочница для безопасного выполнения шаблонов в изолированном окружении. Скорость. Сам Twig написан на чистом php. Компилирует шаблоны в php классы с последующим многократном использованием оных. Из коробки, в некоторых местах, проигрывает по скорости даже Smarty 3. Однако с использованием, идущего в комплекте расширения на C (которое содержит одну единственную функцию :)) можно получить вполне приемлемую производительность. Расширяемость. Тут Twig абсолютный лидер. Он позволяет все: от расширения языковых конструкций до создания своего компилятора шаблонов. Одной из примечательных особенностей можно отметить то, что можно писать расширения, которые будут работать на уровне компиляции. К примеру, не сложно написать расширение, удаляющее лишние пробелы из литералов один раз при компиляции, а не в runtime из всех переменных подряд. Или же можно написать расширение которое будет компилировать тот-же самый шаблон в чистый javascript. Юзабилити. Удобный лаконичный синтаксис. Некоторые конструкции, явно, позаимствованы из питона. Так же как и Smarty интегрируется со многими IDE. Рекомендовал бы для всех проектов не слишком критичных к производительности или требующих очень тесную интеграцию шаблонизатора с основным проектом. Blitz - безумно быстрый шаблонизатор от русского разработчика. Написан на C. Возможности. Блоки, переменные, примитивная конструкция IF и пользовательские функции. Все. Скорость. Это наверное единственный из всех используемых мной шаблонизаторов, который в некоторых случаях (как правило для сложных шаблонов с большим количеством блоков) по скорости превосходит даже php mess! Более быстрого шаблонизатора я еще не встречал. Расширяемость. Единственная возможность расширения - это пользовательские функции. Однако в качестве параметров функций могут выступать только переменные текущего контекста или скалярные литералы, что делает их несколько ограниченными в возможностях. Юзабилити. Синтаксис в виде HTML комментариев, плюс отсутствие всевозможных циклов, сложных ветвлений и т.п делает, на мой взгляд, шаблоны очень удобными для верстки. Ничего лишнего, в браузере сразу видно как будут выглядеть все блоки шаблона. Верстальщику не нужно учить никаких сложных конструкций. Для разработчика же все в точности до наоборот. В связи со спецификой шаблонизатора и ограниченной функциональности нужно подготавливать данные с заранее определенной структурой (см. раздел 15. Nested iterations) или же вводить дополнительную прослойку, отвечающую за логику отображения. Рекомендовал бы для любых highload проектов.

Ответ 2



Я бы использовал нативный шаблон html + php. Это достаточно быстрее чем Смарти, но будет проблематично верстальщику. Для этого код просто выделять в блоки с комментариями.

Ответ 3



За всю свою жизнь не встретил ни одного верстальщика, которому было бы проблематично понять нечто вроде . Ответ на вопрос. Если CMS и правда многоцелевая, то xml. с помощью xslt можно сотворить очень многое.

Ответ 4



Мне лично нравится мой самописный шаблонизатор (могу залить куда-нибудь; документации нет). Весит мало, умеет только то, что нужно: делать include в шаблон, дублировать блоки и вставлять значения в метки. Сами шаблоны напоминают html и не содержат в себе логики. То есть, прогер указывает верстаку, что будет выводиться на странице, а верстак уже решает, где это будет и как.

Ответ 5



Используйте любой шаблонизатор, если вы планируете пользоваться своей CMS больше одного раза :) Лучше всего использовать смарти, по которому много документации и с которым знакомы большинство верстальщиков и программистов. Лучше подключить его сразу, чем потом тратить кучу времени на переделку CMS под корректную работу с шаблонизаторами. Насчет мнения, что смарти много весит и медленно работает - с чего вы взяли? Тем более дешевле прикупить хостинг по-мощнее, чем платить программисту, чтобы он навел порядок в шаблонах ;)

Декомпилятор C#

#c_sharp


Вот скажите, у меня есть одна очень интересная програмка на C#, но вот беда, она
без исходника, так вот, какие есть де компиляторы C#? В инете сейчас искать не могу,
т.к. он лимитный :(    


Ответы

Ответ 1



Попробуйте свободный ILSpy. Список возможностей с их страницы: Assembly browsing IL Disassembly Decompilation to C# Supports lambdas and 'yield return' Shows XML documentation Saving of resources Search for types/methods/properties (substring) Hyperlink-based type/method/property navigation Base/Derived types navigation Navigation history BAML to XAML decompiler Save Assembly as C# Project Find usage of field/method Extensible via plugins (MEF)

Ответ 2



Попробуй JetBrains dotPeek. А еще есть платный Reflector с кучей сладких плюшек им можно пользоваться в триале дней

Деление с округлением в большую сторону

#c_sharp #деление #math


Math.Round округляет по правилу, как заставить его округлять в большую сторону, или
какую другую функцию использовать?    


Ответы

Ответ 1



Math.Ceiling - к большему целому Math.Floor - к меньшему целому

Значение null в java

#null #java #jframe


Скажите, что такое null в java? Пример:
// это только фрагмент
public main() {
    JFrame f = new JFrame();
    f.setLocationRelativeTo(null);
    // и так далее 
}
    


Ответы

Ответ 1



null - читается нал означает отсутствующее значение или ссылку null может быть сконвертирован (кастирован) в любой тип/класс/объект нельзя создать/декларировать тип с типом null

Ответ 2



Это значит отсутствие значения (не 0, а именно отсутствие).

Ответ 3



Первая ссылка в гугле по запросу "null в java". There is also a special null type, the type of the expression null, which has no name. Because the null type has no name, it is impossible to declare a variable of the null type or to cast to the null type. The null reference is the only possible value of an expression of null type. The null reference can always be cast to any reference type. In practice, the programmer can ignore the null type and just pretend that null is merely a special literal that can be of any reference type.

Несколько конструкторов с разным количеством аргументов

#python #ооп


Можно ли в Python в одном классе делать несколько конструкторов с разным количеством
аргументов?
class a:
def __init__(self,b):
    pass
def __init__(self):
    pass

В данном случае можно создавать экземпляры класса только со вторым констуктором,
в то время как запись x = a(42) вызовет ошибку.    


Ответы

Ответ 1



Если быть кратким то НЕТ. Более детально посмотрите обсуждение вот ЗДЕСЬ. Там и варианты решений есть такие как использование необязательных или ключевых аргументов.

Ответ 2



В Python'е перегрузок функций (а конструктор, по факту - это функция) нет в принципе. В вашем случае, вызывается всегда второй конструктор, ибо инструкция def означает "создать объект функции и присвоить этот объект написанному имени", то есть, сначала вы присваиваете имени __init__ одну функцию (с параметром b), а затем - тому же имени - другую функцию, уже без параметра b. Поведение, которого вы добиваетесь, можно получить, используя параметры по умолчанию, например: def __init__(self, b=None): # Здесь лучше придумать что-то отличное от проверки на None # больше соответствующее вашей задаче. Возможно, вам просто подойдет # какое-то значение по умолчанию. if b is None: pass else: pass # ... a = a() # b будет равно None по умолчанию b = a(42) # b будет равно 42

Ответ 3



еще вариант def __init__(self, *args, **kwargs): p = kwargs.get('name','trololo')

Ответ 4



а не проще сделать так: class Troll(): def __init__(self, name='trololo', size=42) # ...... a = Troll() # а тут тролль по умолчанию - trololol, 42 b = Troll('ololol', 12) # тут у нас получиться маленький тролль с ником ололо

Как лучше распараллелить задачу?

#c_sharp #многопоточность


Добрый день!
Есть задача, которую хотелось бы распараллелить.
Имеются функции

y1 = F1(x1, x2, ..., xn),  
y2 = F2(x1, x2, ..., xn)


xi, y1, y2 - вещественные числа;
ОДЗ (область допустимых значений) F1 явл. подмн. ОДЗ F2.  

Задача: перебрать всевозможные наборы (xi), вычислить y1 и y2, зафиксировать (записать
в файл) набор (xi), y1, y2, если |y1 - y2| < e (разница по модулю меньше заданного e).



Выделил следующие функции:
 1. Функция A производит перебор наборов (x1, x2, ..., xn) для y1, является рекурсивной,
не представляю как ее можно привести в другой вид;
Вычисление следующего набора занимает времени меньше чем 0.001 (обычно 0.0002) сек.;
 2. Функция B - вычисление y1, 0.100 - 0.300 сек.;
 3. Функция C - вычисление y2, может быть двух реализаций: 0.100 - 0.200 сек. или
~1-2 сек. - вторую реализацию скорее всего делать не будем.

Вышеописанные измерения только примерные (просто много раз вызывали методы, мерили
при помощи Stopwatch и записывали результат в файл), но описанные диапазоны выдерживают.
Измерения производились на Intel(R) Core(TM) i5 CPU 760  @ 2.80GHz.



Распараллеливание задачи представляю след. образом:
 1. главный поток - выполняет A, результаты складывает в общую для потоков очередь;
 2. функция P - берет очередной набор из очереди, вычисляет y1, y2, сравнивает разницу,
записывает в файл при необходимости;
 3. функцию P запустить в нескольких потоках.



Реализация функций A, B, C уже есть на C#.
С потоками знаком только на WinAPI, прочитал статью на RSDN Работа с потоками в C#.
Есть некоторые представления, про распараллеливание, но хотелось бы добиться максимальной
производительности, т.к. по нашим подсчетам количество всевозможных (xi) больше 10e+9.   

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

UPD
Опечатка: количество всевозможных (xi) больше 10e+9.
    


Ответы

Ответ 1



Почему бы не использовать producer-consumer pattern? Поскольку функции B и C сами по себе быстрые, нужно распараллелить лишь различные вызовы этих функций. Можно сделать так: Поток №1 (producer) вычисляет последовательность наборов x1, x2, ..., xn, используя функцию A. Если вычисление можно распараллелить, вместо потока появляется группа потоков. Результаты складываются в очередь, откуда... Группа потоков №2 (consumer) получает задания из очереди, выполняет для этого набора переменных функцию P, которая вычисляет B, C и сравнивает результаты. Если разность достаточно мала, результат уходит в следующую очередь (для неё текущий поток — producer), откуда... Поток №3 читает данные из очереди и записывает их в файл. Поскольку узким местом, по идее, является вычисление P, количество потоков в группе №2 следует сделать равным количеству ядер в системе.

Ответ 2



Могу предложить следующий quick-and-dirty вариант с использованием Parallel LINQ. Вычисление Y1(arguments), Y2(arguments) и дельты между ними имеет смысл синхронно производить в конструкторе класса Result. Параллелить их выполнение для заданного набора аргументов, а затем как-то reduc'ить результаты кажется мне нецелесообразным. Если реализация вашей функции A не укладывается в логику Range().Select(), то ее стоит переписать с использованием yield return new Arguments(...) и подставить вместо генератора, который приведен в моем примере. Обратите внимание на место, в котором вызывается AsParallel(). В production варианте, наверно, стоит отделить вычисление результатов от их форматирования и записи в файл. var results = Enumerable.Range(0, 1000) .AsParallel() .Select(i => new Arguments(i)) .Select(arguments => new Result(arguments)) .Where(result => result.Delta < Epsilon) .Select(result => result.ToString()); File.WriteAllLines(path, results);

C чего начать изучение UNIX/LINUX? [закрыт]

#книги #unix #linux #debian


        
             
                
                    
                        
                            Закрыт. На этот вопрос невозможно дать объективный ответ.
Ответы на него в данный момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Update the question so it
can be answered with facts and citations by editing this post.
                        
                        Закрыт 4 года назад.
                                                                                
           
                
        
Нужно изучить UNIX.
Я программирую на Java и все наши продукты развернуты на UNIX-стендах. Нужно знать
как оно устроено, команды итд. С точки зрения пользовательских программ - знать не нужно.


Насколько реально изучать UNIX на винде, на которой стоит виртуальная машина? будут
ли какие-то ограничения?


Какую именно версию UNIX лучше поставить для целей изучения? у нас часто используется
Debian, это ок? Там есть какие-нибудь разные editions как у винды?


Какую книжку-две посоветуете для моих целей для изучения с нуля? англ - ок.

    


Ответы

Ответ 1



Есть один проверенный лично метод: Ставьте разные дистрибутивы на реальную тачку: Debian, Fedora, Slackware. В общем главное чтоб дистры были "разные". После установки настраивайте систему под себя: драйвера, GUI, приложения. В таком раскладе как раз столкнетесь и с терминалом, и с особенностями той или иной ОС. Выбрав таким образом понравившийся дистр, попробуйте пользоваться им некоторое время, так и научитесь, со временем. В общем вам поможет практика. UPD Советую не ставить на виртуалку, т.к. в случае возникновения какой-то проблемы будет соблазн дропнуть вирт-машину и вернуться в зону комфорта, вместо того чтобы все исправить.

Ответ 2



Как стать системным администратором или стать на шаг ближе к ним? Этим вопросом задаются многие и единого ответа не существует.. на уровень пользователя - продвинутого пользователя инструкцию Вам описал предыущий оратор гуглите интсрукцию как установить тот или иной дистрибутив качаете чисто консольный пакет без всяких гуевин инсталлите с наименьшим количеством предустановленного по далее решаете поставленные задачи, например: графическую оболку ( несколько разных с попеременным удалением предидущей) далее настраиваем сеть далее дрова в т.ч и вафельные если такое имеется и чем специфичнее у вас конфигурация тем лучше (некоторые radeonовкие карты = 7 кругов ада) после того как у Вас из линуксовой операционки получится столь же удобный и привычный декстоп как на винде ( или отдаленно напоминающий оный ) начинайте настраивать уже сервера и прочие необходимые окружения все это в обнимку с гуглом после этого, в получившейся НеФорточной системе поднимаете виртуалку (она вам пригодится не только для экспериментов), опять же пробуйте разные пока не придет четкое понимание как и с какой работать ( qemu+kvm, VirtualBox, прочие) ну и наверно тут и будет некоторый профит по вашему вопросу, так же рекомендую почитать на досуге книжечку "TCP/IP крупным планом" - это не библия, но знать необходимо

Ответ 3



Несколько тезисов из своего опыта для целей ТС: выбирайте дистрибутив "общего назначения", "универсальный первородный конструктор" - типа Fedora, Debian, Slackware... Не выбирайте производные, а тем более т. н. "кастомные" дистрибутивы используйте этот дистрибутив на реальной машине, желательно в качестве единственной системы перед переходом запаситесь Live-CD с Knoppix, например, для возможности быстрой починки предпочитайте консоль гую редактируйте текстовые файлы нативными консольными средствами читайте встроенную документацию - это информация "из первых рук" не поддавайтесь унынию, если что-то не будет получаться ;-)

Как проверить, что переменная != (степень двойки - 1)

#python


Как написать проверку, что число не является (степенью двойки - 1), не прибегая к
использованию заранее заполненного списка подобных чисел:

f2 = [1,3,7,15]
x = int(input("Задать: "))
if x not in (f2):
    print ("Нет")
else:
    print ("Да")


А как-то с помошью вот этого 

(x != 0) && !(x & (x - 1)


или вот этого

 while (((x % 2) == 0) && x > 1) /* While x is even and > 1 */
   x /= 2;
 return (x == 1);


методов?
    


Ответы

Ответ 1



А так не пойдет? from math import log r = log(a+1)/log(2.) print r!=int(r)

Ответ 2



Ну, буквально на пальцах - нужно было сделать проверку, является ли переменная одним из начений множества ((степень двойки)- 1). Было поздно, меня беспощадно заклинило, и потому не мог сформулировать. Однако пока читал этот пост - расклинило. Получилось примерно так: def po2Minus1 (): global testvalue global limit limit = int(input("Enter upper limit: ")) f = [] x = range(2, limit) for i in (x): if (i and i & (i - 1) == 0): i = i-1 f.append(i) testvalue = int(input("Enter test value: ")) if testvalue not in (f): print ("The number you entered is not a power of 2 minus 1") else: print ("The number you entered is a power of 2 minus 1") Вот. За что всем поучаствовавшим спасибо. Наверняка можно то же самое написать компактней, только я не знаю как.

Ответ 3



У вас уже в самом вопросе приведена проверка того, является ли число степенью двойки. Можно немного её модифицировать и получить то, что требуется. Я использовал подобную схему работы с битами, наверняка её можно улучшить: def check(x): return x ^ (x + 1) == 2 * x + 1 Она основана на том, что в двоичной системе счисления число, равное степени двойки без единицы, представлено в виде последовательности n единиц: 11...111. Добавив единицу к этому числу мы получим число, в записи которого будет одна единица и n нулей: 100...000. Для удобства запишу их друг под другом и сложу их побитово по модулю два: 11...111 + 100...000 = 111...111 Побитовое сложение по модулю два даст в сумме число, равное удвоенному изначальному числу плюс один только в одном случае -- когда были сложены число, равное степени двойки и это же число без единицы. Это довольно несложно понять и доказать. UPD Добавлю из комментария @VlaD упрощённый вариант: def check(x): return not x & (x + 1) Он работает ровно по той же причине, что и код выше.

Ответ 4



Стандартный способ определить является ли целое число степенью двойки: def is_power_two(n): assert n >= 0 return n != 0 and n & (n - 1) == 0 Поэтому чтобы узнать, что переменная является положительной степенью двойки минус один (n -> n+1): def is_pos_power_two_minus_one(n): assert n >= 0 return n != 0 and (n + 1) & n == 0 Обратное условие: def not_pos_power_two_minus_one(n): assert n >= 0 return n == 0 or (n + 1) & n != 0 Пример: for n in range(10): not_ = "not " * not_pos_power_two_minus_one(n) print("{n} {n:04b} is {not_}(2**N - 1)".format(**vars())) Результат 0 0000 is not (2**N - 1) 1 0001 is (2**N - 1) 2 0010 is not (2**N - 1) 3 0011 is (2**N - 1) 4 0100 is not (2**N - 1) 5 0101 is not (2**N - 1) 6 0110 is not (2**N - 1) 7 0111 is (2**N - 1) 8 1000 is not (2**N - 1) 9 1001 is not (2**N - 1) Если разрешить N == 0, то 2**0 == 1 и поэтому ноль является "(степень двойки - 1)". В итоге "переменная != (степень двойки - 1)": def not_power_two_minus_one(n): assert n >= 0 return (n + 1) & n != 0 что совпадает со вторым решением в ответе @Timofey Bondarev. Объяснение Cтепень двойки (2**N) в двоичном представлении это просто единичка c N нулями, например: 2**3 == 0b1000, соответственно "(степень двойки - 1)" (2**N - 1) -- это просто N единичек, например: 2**3 - 1 == 0b0111. Очевидно, что 2**N & (2**N - 1) == 0 (где N >= 0), например: 1000 & 0111 ---- 0000 потому что 0 & 1 == 0, где & это побитовое "и". То есть, если n это степень двойки, то n & (n - 1) == 0. Также верно обратное: если n & (n - 1) == 0 для положительного целого числа n, то n это степень двойки («от противного» можно доказать). Таким образом, n & (n - 1) == 0 условие является необходимым и достаточным для положительных целых чисел, чтобы определить, что n -- это степень двойки (2**N).

Использование метода sleep()

#java #многопоточность #sleep


Всем добрый день. Нужен совет: программа должна менять надпись на кнопке последовательно
от "10" до "0". Чтобы каждая смена надписи происходила с небольшим интервалом я использовал
метод sleep().

В итоге после нажатия кнопки прога подвисает и затем сразу выдает "0". В чём может
быть проблема? Кусок кода представлен ниже.

try {
    for (int i = 10; i > -1; i--) {
        Thread.sleep(500);
        String iString = String.valueOf(i);
        button.setText(iString);
    }
} catch (InterruptedException qq) {
    qq.printStackTrace();
}
    


Ответы

Ответ 1



Добро пожаловать в увлекательный мир UI-программирования! Вам придётся немного переучиться: здесь всё не так, как в программах командной строки. Здесь все фоновые задания, связанные с интерфейсом, происходят не немедленно, как только вы скомандовали, а вперемешку с вашей работой. Всё это происходит в фиксированном потоке, так называемом UI-потоке. Что происходит в вашем коде? Вы блокируете UI-поток на полсекунды, затем устанавливаете текст кнопки. Устанавливается внутренний флаг в графической библиотеке, который говорит «когда будет свободная минутка, надо обновить button». Вы немедленно снова блокируете UI-поток на полсекунды, и переустанавливаете текст кнопки. Поскольку «свободная минутка» (она же «idle loop») так и не наступила, текст обновиться не успел. Кроме того, на время блокировки некому обрабатывать события от мыши и клавиатуры (потому что UI-поток занят sleep'ом), так что программа выглядит зависшей. Затем вы опять устанавливаете текст кнопки, это ничего не меняет, так как флаг, указывающий необходимость обновления, уже взведён. И так далее, 11 раз. В конце-концов, когда ваш цикл закончился, UI-поток наконец-то освободился, и может отрисовать ваши изменения. Вы наконец-то видите 0. В чём суть проблемы? Вы не должны совершать длинные операции в UI-потоке. Thread.sleep — одна из таких операций, но многие ещё и читают файлы, грузят данные из сети или обращаются к базе данных. Вы имеете право загружать UI-поток работой лишь на несколько миллисекунд. На всё время длинной операции, бегущей в UI-потоке, приложение будет выглядеть зависшим, и обработчики UI-событий вызываться не будут. Такое поведение программы сразу превращает её в студенческую поделку. Обновление UI, реакция на мышь, перерисовка контролов — всё происходит в UI-потоке, в тот момент, когда этот поток ничем не занят. Хорошая программа с UI должна быть событийно-ориентированной, а не императивной: вы должны не сами рулить ходом программы, а лишь реагировать на события короткими по времени обработчиками. Что нужно делать? Есть два пути. Простой путь, который вполне подходит для ваших целей: не блокируете UI-поток, а используете таймер, который идёт с вашей UI-библиотекой. Он вызовет ваш обработчик в нужное время, вы установите там текст кнопки, и закончите обработку. тем самым вы отпустите UI-поток, чтобы он смог обновить UI. Сложный путь, который применяется, если вам действительно нужно выполнить длительную операцию. В этом случае вы создаёте отдельный поток (thread), в котором и выполняете нужную операцию. Результаты работы вы в нужный момент посылаете в UI-поток, который должен просто обновить UI. Заметьте, что в этом случае программирование становится намного сложнее, так как вам придётся заботиться о синхронизациях, блокировках и коммуникации между потоками (просто глобальная переменная не катит). Но для вашего случая это лишнее, вполне хватит простого таймера.

Ответ 2



А так если? Thread th = new Thread(new Runnable() { for (int i = 10; i > -1; i--) { String iString = String.valueOf(i); button.setText(iString); sleep(1000); } }); th.start();

Как убрать файл, который уже есть в .gitignore?

#git #gitignore


Как убрать workspace.xml, чтобы он не индексировался?

В .gitignore написано

.idea/workspace.xml
/.idea/workspace.xml
.idea
/.idea
*/.idea/workspace.xml


но она все равно индексируется.
    


Ответы

Ответ 1



наболее краткий вариант (всего две изменяющие что-либо команды) рекурсивно удаляем из репозитория каталог (рабочая копия не затрагивается — меняется только содержимое индекса): $ git rm -r --cached .idea перед git commit всегда полезно посмотреть git status и убедиться, что всё идёт так, как надо: $ git status On branch master Changes to be committed: (use "git reset HEAD ..." to unstage) deleted: .idea/workspace.xml всё в порядке. делаем commit. рабочая копия тем более не затрагивается — меняется содержимое репозитория (всего того, что находится в каталоге .git): $ git commit ... проверяем: $ ls .idea workspace.xml да, файл на месте. а в .gitignore достаточно оставить одну строку (из всех озвученных в вопросе): .idea

Ответ 2



Видимо, файлам уже был ранее сделан commit, поможет mv .idea .idea1 git rm -r .idea git commit [--amend] mv .idea1 .idea Либо правка ранее сделанных коммитов git rebase -i ... и там git rm -r --cached .idea

Ошибка при авторизации в VK через приложение на node.js

#nodejs #vkontakte_api #express


Добрый день, товарищи!

Возникла проблема - не могу справиться с авторизацией через ВК в своем приложении
(node.js + express.js + passport.js). При попытке авторизации браузер показывает следующее
сообщение:


  {"error":"invalid_request","error_description":"redirect_uri is
  incorrect, check application domain in the settings page"}


Все делал по примеру c данной страницы: Passport-VKontakte
    


Ответы

Ответ 1



Убедитесь, что у вас адрес домена в redirect_url и базовый домен в приложении (в вконтакте) совпадают.

Ответ 2



Если кто-то в будущем столкнется с этой проблемой, возможно вам поможет следующее: Убедитесь, что тип созданного вами приложения во Вконтакте поддерживает стороннюю авторизацию: standalone или веб-сайт Для standalone приложений убедитесь, что в настройках приложения взведена галочка open API. Пусть вас не смущает, что open API не имеет ничего общего с Oauth2. Если вы размещаете приложение на кириллическом домене, в настройках должен быть указан домен приложения именно в кириллическом наборе, а не в punycode. Да, фактически вариант punycode должен быть тождественным кириллице, но во Вконтакте вот так вот сложилось.

Ответ 3



Мне не удалось решить проблему вот так: Нужно в настройках приложения Вконтакте сделать пустым поле Доверенный redirect URI:. После этого у меня все заработало.

Ответ 4



При использовании API в мобильном приложении заработало после того как стал передавать пустой redirect_uri. Пример запроса: https://oauth.vk.com/authorize?client_id=123456&redirect_uri=&response_type=token&scope=0&v=5.92

Отключить обновление страницы, после отправки формы

#javascript #html #canvas


При отправке формы, на странице должен отрисовываться canvas. Но после того как форма
отправлена, canvas отрисовывается на долю секунды и потом исчезает. Как сделать так,
чтобы после отправки, canvas оставался на месте.

html code:

Enter math expression:
js: function drawShelves() { var canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'); canvas.width = 800; canvas.height = 400; ctx.lineWidth = 1.0; ctx.strokeStyle = 'black'; ctx.beginPath(); // left shelve ctx.strokeRect(5, 100, 340, 10); ctx.moveTo(5, 110); for (var i = 5; i < 340; i+=10) { ctx.lineTo(i+10, 100); ctx.moveTo(i+10, 110); } // right shelve ctx.strokeRect(455, 100, 340, 10); ctx.moveTo(455, 110); for (var i = 455; i < 790; i+=10) { ctx.lineTo(i+10, 100); ctx.moveTo(i+10, 110); } ctx.stroke(); }


Ответы

Ответ 1



Есть два варианта. Отключить событие нажатия на кнопку по умолчанию: Отключить событие отправки формы по умолчанию:
Но в обоих случаях вам нужно каким-либо образом без перезагрузки страницы отправить данные на сервер. Самый верный способ -- использовать Ajax запрос. Поэтому код будет проще переписать следующим образом: function drawShelves() { // здесь отрисовка канвы // здесь ajax запрос return false; } Подробнее про Ajax можно прочитать здесь: http://javascript.ru/ajax/intro.

Ответ 2



...function(event) { // Откоючает тригер события формы event.preventDefault(); ... some code... }

preg_match понимает не все русские буквы

#php #регулярные_выражения


Почему может быть, что  

preg_match('/^[а-яА-ЯЁёa-zA-Z0-9_]+$/', $userName)


возвращает true для буквы "ПП","пп","УУ","еe","яя" и false для "тт", "уу","юю" и
других?  

Кодировка UTF-8. Php 5.2.17

Также я заметил, что strlen($userName), например, для "пп" = 4, а для "уу" = 2.

П.С. При этом  

preg_match('/^[_0-9A-Za-zА-Яа-пр-яЁё]+$/', $userName)


работает.
    


Ответы

Ответ 1



В PHP Регулярные выражения не работают с русскими буквами. Для работы с ними нужно использовать модификатор /u u (PCRE_UTF8) Этот модификатор включает дополнительную функциональность PCRE, которая не совместима с Perl: шаблон и целевая строка обрабатываются как UTF-8 строки. Модификатор u доступен в PHP 4.1.0 и выше для Unix-платформ, и в PHP 4.2.3 и выше для Windows платформ. Валидность UTF-8 в шаблоне и целевой строке проверяется начиная с PHP 4.3.5. Недопустимая целевая строка приводит к тому, что функции preg_* ничего не находят, а неправильный шаблон приводит к ошибке уровня E_WARNING. Пятый и шестой октеты UTF-8 последовательности рассматриваются недопустимыми с PHP 5.3.4 (согласно PCRE 7.3 2007-08-28); ранее они считались допустимыми. Источник Пример: preg_match( '/^([а-яА-ЯЁёa-zA-Z0-9_]+)$/u', $userName)

Ответ 2



На счет разного результата strlen - для utf-8 следует использовать mb_strlen.

Нарисовать Землю с помощью OpenGL

#qt #opengl #карты


Рисую с помощью OpenGL в Qt плоскую и 3Д Землю. На данный момент в качестве текстуры
используется растровое изображение. Хочется, чтобы была возможность увеличивать карту
с детализацией изображения.
С чего начать? Может какие-то статьи или книги есть на подобную тему? Сама в интернете
ничего не нашла.
    


Ответы

Ответ 1



Хранить географические карты в растре? Вы серьезно? Начать нужно с того что: Где-то достать растровую плоскую физическую карту мира Сконвертировать её в нормализованную 8 битную карту высот. (уже кто-то сделал) C помощью displacement mapping получить полигональную сетку из растровой карты высот. Спроецировать полученную сетку на сферу с помощью функции обратной, той что использовалась при развертке сферы в карту. (Картографические проекции достаточно сложны, однако по ним есть много информации) В конце в качестве diffuse map использовать оригинальную карту. Также можно еще взять случайную карту нормалей и добавить немного bump mappingа в получившийся ландшафт. В результате может-быть получится более менее сносная картинка, которую можно нормально скалировать, вращать, бомбить трехмерными ядерными ракетами, заселять виртуальными горожанами, насылать нашествие инопланетян и.т.д. и.т.п. Вот еще годная статья по поводу сравнения методов рельефного текстурирования. Также есть много софта для получения сетки рельефа напрямую из карты высот. Нарпимер всем известный Terragen. С ним генерация картинок вроде такой становится тривиальной задачей вообще не требующей значительных художественных навыков: И еще подборка статей про алгоритмическую генерацию рельефа местности: Как это делают в NVIDIA Фрактальная генерация Получение своих континетов для новичков Хороший пример генерации через WebGL размером всего в 130 строчек JS Обзорная презентация. Мало формул, много примеров и названий технологий Также имеет смысл ознакомится с различными методами генерации градиентных шумов, чтобы с помощью них получить свою случайную карту нормалей/высот и сделать ландшафт еще более реалистичным.

Ответ 2



Если нужно детализировать текстуру то используй MIP mapping

Как заставить .NET оптимизировать код?

#c_sharp #net


Сравнивая производительность 

public static int GetR(int argb)
{
    return (argb >> 16) & 0xff;
}
...
for (int i = 0; i < max; i++)
{
    temp1 = GetR(i);
}


и 

for (int i = 0; i < max; i++)
{
    temp2 = (i >> 16) & 0xff;
}


Обнаружил, что первый способ работает чуть медленнее. По дизассемблированному коду
studio видно, что метод не подставляется inline.
Неужели такие простые методы не делаются inline?
.Net 4.5 (интересует также для .Net 4.0 и желательно для 3.5, 2.0), компилирую в
стандартной конфигурации Release VS2012.  

Аналогично:

public static int BuildArgb(int alpha, int red, int green, int blue)
{
    return (red << 16) | (green << 8) | (blue << 0) | (alpha << 24);
}

... 
for (int i = 0; i < sz; i++)
{
    color = BuildArgb(aBytes[i], rBytes[i], gBytes[i], bBytes[i]);
}


и 

for (int i = 0; i < sz; i++)
{
    color = (rBytes[i] << 16) | (gBytes[i] << 8) | (bBytes[i]) | (aBytes[i] << 24);
}


Можно ли попросить компилятор оптимизировать код ?

UPD
Код измерений для второго примера:

private static void Test3(int sz)
{
    Console.WriteLine("Test BuildArgb");

    Random random = new Random(255);
    byte[] aBytes = new byte[sz];
    byte[] rBytes = new byte[sz];
    byte[] gBytes = new byte[sz];
    byte[] bBytes = new byte[sz];
    for (int i = 0; i < sz; i++)
    {
        aBytes[i] = (byte)random.Next();
        rBytes[i] = (byte)random.Next();
        gBytes[i] = (byte)random.Next();
        bBytes[i] = (byte)random.Next();
    }

    int color = 0;

    var s2 = Stopwatch.StartNew();
    for (int i = 0; i < sz; i++)
    {
        color = BuildArgb(aBytes[i], rBytes[i], gBytes[i], bBytes[i]);
    }

    s2.Stop();

    var s3 = Stopwatch.StartNew();
    for (int i = 0; i < sz; i++)
    {
        color = (rBytes[i] << 16) | (gBytes[i] << 8) | (bBytes[i] << 0) | (aBytes[i]
<< 24);
    }

    s3.Stop();

    Console.WriteLine("BuildArgb: " + s2.Elapsed.TotalMilliseconds);
    Console.WriteLine("Inline: " + s3.Elapsed.TotalMilliseconds);
    Console.WriteLine(color);
}


UOD 2 

Полный код примера 2

namespace ConsoleApplication1
{
    using System;

    using System.Diagnostics;

    internal class Program
    {
        public static int BuildArgb(int alpha, int red, int green, int blue)
        {
            return (red << 16) | (green << 8) | (blue << 0) | (alpha << 24);
        }

        private static void Main()
        {
            const int max = int.MaxValue;

            //Test1(max);
            //Test2(1024 * 1024 * 100);
            Test3(1024 * 1024 * 100);

            Console.Read();
        }           

        private static void Test3(int sz)
        {
            Console.WriteLine("Test BuildArgb");

            Random random = new Random(255);
            byte[] aBytes = new byte[sz];
            byte[] rBytes = new byte[sz];
            byte[] gBytes = new byte[sz];
            byte[] bBytes = new byte[sz];
            for (int i = 0; i < sz; i++)
            {
                aBytes[i] = (byte)random.Next();
                rBytes[i] = (byte)random.Next();
                gBytes[i] = (byte)random.Next();
                bBytes[i] = (byte)random.Next();
            }

            int color = 0;

            var s2 = Stopwatch.StartNew();
            for (int i = 0; i < sz; i++)
            {
                color = BuildArgb(aBytes[i], rBytes[i], gBytes[i], bBytes[i]);
            }

            s2.Stop();

            var s3 = Stopwatch.StartNew();
            for (int i = 0; i < sz; i++)
            {
                color = (rBytes[i] << 16) | (gBytes[i] << 8) | (bBytes[i] << 0) |
(aBytes[i] << 24);
            }

            s3.Stop();

            Console.WriteLine("BuildArgb: " + s2.Elapsed.TotalMilliseconds);
            Console.WriteLine("Inline: " + s3.Elapsed.TotalMilliseconds);
            Console.WriteLine(color);  // Использование переменной, что бы циклы
не скомпилировались пустыми
        }
    }
}


UPD 3
Тестовый код нужно подкорректировать, результат переменной color зависит только от
второго цикла, что может повлечь оптимизации, которые повлияют на результаты тестов.
После корректировки результат почти одинаковый - в пределах погрешности.
    


Ответы

Ответ 1



Неужели такие простые методы не делаются inline? Во втором примере JIT вполне успешно инлайнит метод при запуске в конфигурации Release не под отладкой. Более того, полученный нативный код практически совпадает для первого и второго вариантов, отличается лишь порядок применения сдвигов. Это можно легко проверить: Дописать Debugger.Launch(); где-то в теле Test3 Выбрать конфигурацию Release Запустить не под отладчиком В появившемся окне выбрать уже открытых экземпляр студии Кликнуть правой кнопкой рядом с местом остановки, выбрать Go To Disassembly Для второго случая результат примерно такой: for (int i = 0; i < sz; i++) { temp1 = GetR(i); } превратилось в for (int i = 0; i < sz; i++) 00E6055A xor eax,eax for (int i = 0; i < sz; i++) 00E6055C test ebx,ebx 00E6055E jle 00E60570 00E60560 mov ecx,eax 00E60562 sar ecx,10h 00E60565 and ecx,0FFh 00E6056B inc eax 00E6056C cmp eax,ebx 00E6056E jl 00E60560 } а второй цикл for (int i = 0; i < sz; i++) { temp2 = (i >> 16) & 0xff; } превратился в for (int i = 0; i < sz; i++) 00E60570 xor eax,eax for (int i = 0; i < sz; i++) 00E60572 test ebx,ebx 00E60574 jle 00E60586 { temp2 = (i >> 16) & 0xff; 00E60576 mov edx,eax 00E60578 sar edx,10h 00E6057B and edx,0FFh for (int i = 0; i < sz; i++) 00E60581 inc eax 00E60582 cmp eax,ebx 00E60584 jl 00E60576 } Как видно, результат полностью одинаковый - так что любая разница - это просто погрешность измерений. Само интересное, что если temp1 и temp2 не используются после из расчета, то JIT просто выбрасывает сам расчет: for (int i = 0; i < sz; i++) 0062054E xor eax,eax for (int i = 0; i < sz; i++) 00620550 test ebx,ebx 00620552 jle 00620559 00620554 inc eax 00620555 cmp eax,ebx 00620557 jl 00620554 } Вы же используете temp1 и temp2 после тела цикла? Если нет - то вы просто измеряете скорость перемотки цикла. Для второго примера картина та же - ассемблерный код практически совпадает, отличается лишь порядок применения сдвигов: for (int i = 0; i < sz; i++) xor edx,edx test ebx,ebx jle 00ED063E mov eax,dword ptr [ebp-28h] { color = Argb32Helper.MakeArgb(aBytes[i], rBytes[i], gBytes[i], bBytes[i]); mov eax,dword ptr [ebp-28h] cmp edx,dword ptr [eax+4] jae 00ED077F movzx eax,byte ptr [eax+edx+8] mov dword ptr [ebp-24h],eax mov eax,dword ptr [ebp-2Ch] cmp edx,dword ptr [eax+4] jae 00ED077F movzx esi,byte ptr [eax+edx+8] mov eax,dword ptr [ebp-30h] cmp edx,dword ptr [eax+4] jae 00ED077F movzx ecx,byte ptr [eax+edx+8] mov eax,dword ptr [ebp-34h] cmp edx,dword ptr [eax+4] jae 00ED077F movzx edi,byte ptr [eax+edx+8] { color = Argb32Helper.MakeArgb(aBytes[i], rBytes[i], gBytes[i], bBytes[i]); mov eax,dword ptr [ebp-24h] shl eax,10h shl esi,8 or eax,esi or eax,ecx shl edi,18h or eax,edi mov dword ptr [ebp-10h],eax for (int i = 0; i < sz; i++) inc edx cmp edx,ebx jl 00ED05DD } call нет, метод заинлайнен. для второго цикла: for (int i = 0; i < sz; i++) xor ecx,ecx test ebx,ebx jle 00ED06EB mov eax,dword ptr [ebp-2Ch] { color = (rBytes[i] << 16) | (gBytes[i] << 8) | (bBytes[i] << 0) | (aBytes[i] << 24); mov eax,dword ptr [ebp-2Ch] cmp ecx,dword ptr [eax+4] jae 00ED077F movzx eax,byte ptr [eax+ecx+8] shl eax,10h mov edx,dword ptr [ebp-30h] cmp ecx,dword ptr [edx+4] jae 00ED077F movzx edx,byte ptr [edx+ecx+8] shl edx,8 or eax,edx mov edx,dword ptr [ebp-34h] cmp ecx,dword ptr [edx+4] jae 00ED077F movzx edx,byte ptr [edx+ecx+8] or eax,edx mov edx,dword ptr [ebp-28h] cmp ecx,dword ptr [edx+4] jae 00ED077F movzx edx,byte ptr [edx+ecx+8] shl edx,18h or eax,edx mov dword ptr [ebp-10h],eax for (int i = 0; i < sz; i++) inc ecx cmp ecx,ebx jl 00ED0690 } Разница в выполнении чуть заметна, и зависит от порядка вызова циклов - тот, что вызывается первым, всегда немного медленее - именно поэтому в тестах всегда надо делать разогрев. Бонус: для совсем нового JIT из 4.6 на моей машине код совпадает еще больше - тело цикла будет состоит из 4-х блоков вида mov eax,dword ptr [rbx+8] cmp ecx,eax jae 00007FF805D207F8 movsxd rax,ecx movzx eax,byte ptr [rbx+rax+10h] и отличается только порядком блоков. первая проверка - mov/cmp/jae - это проверка выхода за границы массива. Формально она выполняется в цикле 4 раза, что должно добавлять тормозов. Но на практике этот переход очень хорошо предсказывается современными процессорами. Так что практически цикл просто читает данные из массивов и пишет их в соответствующие байты результата.

Ответ 2



Заставить не получится. Если вы хотите указать компилятору чтобы он по возможности заинлайнл вызов метода, используйте атрибут [MethodImpl(MethodImplOptions.AggressiveInlining)] Работает с версии 4.5. Вот тут более подробно: Aggressive Inlining in the CLR 4.5 JIT. UPD. По дизассемблированному коду studio видно, что метод не подставляется inline. Проверять это рефлектором бесполезно. Данная оптимизация происходит на этапе JIT, который преобразует промежуточный язык .NET в машинный код.

Нужно ли удалять ветку после слияния её с другой?

#git #git_branch


В проекте есть ветка master. От нее ответвлена dev, а от dev идут ветки отдельных
фиксов, назовем fix.
Т.е. проект выглядит как master -> dev -> fix. После объединения веток dev и fix,
в репозитории сохранилась ветка fix.

git checkout dev
git merge master
<<тут изменения при слиянии>>
git branch
> fix
>*dev
> master


Надо ли ее удалять или она так и должна висеть там? 
    


Ответы

Ответ 1



Можно вполне спокойно удалить. Многие так и делают, что бы просто не мозолило глаза в списке веток. Тем не менее, это совершенно не обязательно - если не хотите, можете и оставить. Ну и естественно не стоит удалять постоянные ветки, которые в команде условлено использовать для постоянного процесса разработки, например созданные для соответствия тому-же Gitflow Workflow. Т.е. если вы скажем, влили ветку develop в master, закончив работу над некой функциональностью, то постоянно удалять ветвь develop после слияния - крайне глупая затея.

Ответ 2



В большинстве случаев, после слияния можно безопасно удалить отработанную ветку git branch -d имяВетки В случае если git посчитает что ветка не была полностью слита, он покажет предупреждение и откажется удалять ветвь. Если вы уверены что нужно удалить ветвь (используя git branch -D имяВетки) которая еще не полностью объединена, вам нужно сделать несколько дополнительных действий чтобы привести в порядок необъединенные коммиты. Есть ряд случаев когда ветвь рекомендуется сохранить. Например, если это ветка новых возможностей (новых фич), то возможно вы захотите делать правки этой возможности (фичи) внутри объединенной ветки. Это перевод ответа Jonas Wielicki https://stackoverflow.com/a/14005910

Подгрузка данных в RecyclerView

#android #json #recyclerview


Реализовал приложение которое грузит статьи с сайта. Статей 400+ через JSON гружу
последние 10. Остальные планирую грузить другим отдельным таском по запросу пользователя.
Вопрос:
Как прикрутить кнопку в низу RecyclerView, что бы можно было при желании подгрузить
следующие 10 статей. Или может что то другое посоветуете?
    


Ответы

Ответ 1



Для автоматической подгрузки, если пользователь прокрутил список до конца, вам нужно использовать кастомный OnScrollListener RecyclerView.OnScrollListener scrollListener = new OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int visibleItemCount = layoutManager.getChildCount();//смотрим сколько элементов на экране int totalItemCount = layoutManager.getItemCount();//сколько всего элементов int firstVisibleItems = layoutManager.findFirstVisibleItemPosition();//какая позиция первого элемента if (!isLoading) {//проверяем, грузим мы что-то или нет, эта переменная должна быть вне класса OnScrollListener if ( (visibleItemCount+firstVisibleItems) >= totalItemCount) { isLoading = true;//ставим флаг что мы попросили еще элемены if(loadingListener != null){ loadingListener.loadMoreItems(totalItemCount);//тут я использовал калбэк который просто говорит наружу что нужно еще элементов и с какой позиции начинать загрузку } } } } }; Не забываем назначить его _recyclerView.setOnScrollListener(scrollListener); Есть небольшая особенность, этот код не будет работать с StaggeredGridLayoutManager Грузите следующую партию статей и добавляете в адаптер, после добавления вызываете у адаптера notifyDataSetChanged() и ставите флаг isLoading = false В адаптере вам нужно сделать что бы его размер был (реальный размер + 1) и отображать последний элемент как индикатор загрузки.

Ответ 2



Ловить момент, когда следует подгружать данные, можно двумя способами: 1) Как и писал SorryForMyEnglish, повесить на RecyclerView слушатель прокрутки и, когда он будет прокручен до последнего элемента, подгружать новую порцию данных. Вот пример реализации такого способа: https://github.com/ziginsider/DynamicLoadingRecyclerView 2) В адаптере можно получить позицию только что появившегося элемента списка. Если позиция появившегося элемента последняя, значит пора подгружать новую порцию данных: @Override public void onViewAttachedToWindow(final ViewHolder holder) { super.onViewAttachedToWindow(holder); int layoutPosition = holder.getLayoutPosition(); // тут проверяем не последний ли элемент и запускаем калбэк // аналогично первому способу }

Ответ 3



Можно вообще ловить это дело в onBindViewHolder Но сначала интерфейс создайте в адаптере public interface OnLoadMoreListener { void onLoadMore(); } Переменную private OnLoadMoreListener onLoadMoreListener; Ну и сеттер для неё public void setOnLoadMoreListener(OnLoadMoreListener listener) { this.onLoadMoreListener = listener; } Теперь создадим в адаптере переменные isLoading и noMore. Первая нужна будет для того, чтобы избежать бага "почему айтемы копируются", а вторая чтобы избежать `почему он вечно крутится". private boolean isLoading, noMore; Сеттеры для них public void endLoading() { this.isLoading = false; } public void setNoMore(boolean noMore) { this.noMore = noMore; } Теперь в onBindViewHolder можно написать так: public void onBindViewHolder(...) { //ваш биндинг if(onLoadMoreListener != null && !isLoading && !noMore && holder.getAdapterPosition() == getItemCount() - 1) { isLoading = true; onLoadMoreListener.onLoadMore(); } } В активности вешаем на адаптер созданный слушатель и в onLoadMore пишем подгрузку, добавляем то что погрузили в общую коллекцию и обновляем список recyclerViewAdapter.setOnLoadMoreListener(new OnLoadMoreListener() { @Override public void onLoadMore() { List newBooks = //допустим книги и допустим вы их подгрузили totalBooks.addAll(newBooks); //totalBooks это коллекция книг которая содержит все данные для списка recyclerView.notifyDataSetChanged(); recyclerViewAdapter.endLoading(); //когда загрузка завершена recyclerViewAdapter.setNoMore(true); //если подгружать больше нечего } }