Страницы

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

пятница, 20 декабря 2019 г.

Повторная установка свойств в DataTemplate при смене активной вкладки в TabControl

#c_sharp #wpf


В программе используется TabControl и каждая его вкладка представлена юзерконтролом
с таблицей DataGrid. 

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

В коде при этом ничего не изменяется. 

В чем проблема?

MainWindow:


    
        
    



UserControl:


    
        
    


    


Ответы

Ответ 1



Дело в том, что TabControl старается использовать один и тот же контрол для контента всех табов. В связи с этим, конечно, визуальное состояние теряется. Я для себя эту проблему решал так: У TabControl убрал контент, оставил только табы. Поскольку стандартный TabControl оставляет место, пришлось добавить отрицательный отступ снизу. Под TabControl'ом расположил Grid, в котором хранились все View для контента табов, показ нужного проводился через переключение Visibility. Чтобы не делать это вручную, я использовал стандартный трюк с ItemsControl'ом ListBox'ом. Вот полный код: VM-классы: class VM { } class VM1 : VM { public string Header { get { Debug.Print("VM1.Header.get"); return "Что-то"; } } public string Content { get { Debug.Print("VM1.Content.get"); return "В лесу родилась ёлочка"; } } } class VM2 : VM { public string Header { get { Debug.Print("VM2.Header.get"); return "Кто-то"; } } public string Content { get { Debug.Print("VM2.Content.get"); return "И Гена-крокодил"; } } } DataContext: new VM[] { new VM1(), new VM2() } Результат: При этом геттеры срабатывают только по разу, что можно видеть в логе.

Ответ 2



Проблема решена благодаря этому ответу на английской версии SO. Спасибо @Monk. XAML: Code-behind: public static class TabContent { public static bool GetIsCached(DependencyObject obj) { return (bool)obj.GetValue(IsCachedProperty); } public static void SetIsCached(DependencyObject obj, bool value) { obj.SetValue(IsCachedProperty, value); } /// /// Controls whether tab content is cached or not /// /// When TabContent.IsCached is true, visual state of each tab is preserved (cached), even when the tab is hidden public static readonly DependencyProperty IsCachedProperty = DependencyProperty.RegisterAttached("IsCached", typeof(bool), typeof(TabContent), new UIPropertyMetadata(false, OnIsCachedChanged)); public static DataTemplate GetTemplate(DependencyObject obj) { return (DataTemplate)obj.GetValue(TemplateProperty); } public static void SetTemplate(DependencyObject obj, DataTemplate value) { obj.SetValue(TemplateProperty, value); } /// /// Used instead of TabControl.ContentTemplate for cached tabs /// public static readonly DependencyProperty TemplateProperty = DependencyProperty.RegisterAttached("Template", typeof(DataTemplate), typeof(TabContent), new UIPropertyMetadata(null)); public static DataTemplateSelector GetTemplateSelector(DependencyObject obj) { return (DataTemplateSelector)obj.GetValue(TemplateSelectorProperty); } public static void SetTemplateSelector(DependencyObject obj, DataTemplateSelector value) { obj.SetValue(TemplateSelectorProperty, value); } /// /// Used instead of TabControl.ContentTemplateSelector for cached tabs /// public static readonly DependencyProperty TemplateSelectorProperty = DependencyProperty.RegisterAttached("TemplateSelector", typeof(DataTemplateSelector), typeof(TabContent), new UIPropertyMetadata(null)); [EditorBrowsable(EditorBrowsableState.Never)] public static TabControl GetInternalTabControl(DependencyObject obj) { return (TabControl)obj.GetValue(InternalTabControlProperty); } [EditorBrowsable(EditorBrowsableState.Never)] public static void SetInternalTabControl(DependencyObject obj, TabControl value) { obj.SetValue(InternalTabControlProperty, value); } // Using a DependencyProperty as the backing store for InternalTabControl. This enables animation, styling, binding, etc... [EditorBrowsable(EditorBrowsableState.Never)] public static readonly DependencyProperty InternalTabControlProperty = DependencyProperty.RegisterAttached("InternalTabControl", typeof(TabControl), typeof(TabContent), new UIPropertyMetadata(null, OnInternalTabControlChanged)); [EditorBrowsable(EditorBrowsableState.Never)] public static ContentControl GetInternalCachedContent(DependencyObject obj) { return (ContentControl)obj.GetValue(InternalCachedContentProperty); } [EditorBrowsable(EditorBrowsableState.Never)] public static void SetInternalCachedContent(DependencyObject obj, ContentControl value) { obj.SetValue(InternalCachedContentProperty, value); } // Using a DependencyProperty as the backing store for InternalCachedContent. This enables animation, styling, binding, etc... [EditorBrowsable(EditorBrowsableState.Never)] public static readonly DependencyProperty InternalCachedContentProperty = DependencyProperty.RegisterAttached("InternalCachedContent", typeof(ContentControl), typeof(TabContent), new UIPropertyMetadata(null)); [EditorBrowsable(EditorBrowsableState.Never)] public static object GetInternalContentManager(DependencyObject obj) { return (object)obj.GetValue(InternalContentManagerProperty); } [EditorBrowsable(EditorBrowsableState.Never)] public static void SetInternalContentManager(DependencyObject obj, object value) { obj.SetValue(InternalContentManagerProperty, value); } // Using a DependencyProperty as the backing store for InternalContentManager. This enables animation, styling, binding, etc... public static readonly DependencyProperty InternalContentManagerProperty = DependencyProperty.RegisterAttached("InternalContentManager", typeof(object), typeof(TabContent), new UIPropertyMetadata(null)); private static void OnIsCachedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) { if (obj == null) return; var tabControl = obj as TabControl; if (tabControl == null) { throw new InvalidOperationException("Cannot set TabContent.IsCached on object of type " + args.NewValue.GetType().Name + ". Only objects of type TabControl can have TabContent.IsCached property."); } bool newValue = (bool)args.NewValue; if (!newValue) { if (args.OldValue != null && ((bool)args.OldValue)) { throw new NotImplementedException("Cannot change TabContent.IsCached from True to False. Turning tab caching off is not implemented"); } return; } EnsureContentTemplateIsNull(tabControl); tabControl.ContentTemplate = CreateContentTemplate(); } private static DataTemplate CreateContentTemplate() { const string xaml = ""; var context = new ParserContext(); context.XamlTypeMapper = new XamlTypeMapper(new string[0]); context.XamlTypeMapper.AddMappingProcessingInstruction("b", typeof(TabContent).Namespace, typeof(TabContent).Assembly.FullName); context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation"); context.XmlnsDictionary.Add("b", "b"); var template = (DataTemplate)XamlReader.Parse(xaml, context); return template; } private static void OnInternalTabControlChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) { if (obj == null) return; var container = obj as Decorator; if (container == null) { var message = "Cannot set TabContent.InternalTabControl on object of type " + obj.GetType().Name + ". Only controls that derive from Decorator, such as Border can have a TabContent.InternalTabControl."; throw new InvalidOperationException(message); } if (args.NewValue == null) return; if (!(args.NewValue is TabControl)) { throw new InvalidOperationException("Value of TabContent.InternalTabControl cannot be of type " + args.NewValue.GetType().Name + ", it must be of type TabControl"); } var tabControl = (TabControl)args.NewValue; var contentManager = GetContentManager(tabControl, container); contentManager.UpdateSelectedTab(); } private static ContentManager GetContentManager(TabControl tabControl, Decorator container) { var contentManager = (ContentManager)GetInternalContentManager(tabControl); if (contentManager != null) { /* * Content manager already exists for the tab control. This means that tab content template is applied * again, and new instance of the Border control (container) has been created. The old container * referenced by the content manager is no longer visible and needs to be replaced */ contentManager.ReplaceContainer(container); } else { // create content manager for the first time contentManager = new ContentManager(tabControl, container); SetInternalContentManager(tabControl, contentManager); } return contentManager; } private static void EnsureContentTemplateIsNull(TabControl tabControl) { if (tabControl.ContentTemplate != null) { throw new InvalidOperationException("TabControl.ContentTemplate value is not null. If TabContent.IsCached is True, use TabContent.Template instead of ContentTemplate"); } } public class ContentManager { TabControl _tabControl; Decorator _border; public ContentManager(TabControl tabControl, Decorator border) { _tabControl = tabControl; _border = border; _tabControl.SelectionChanged += (sender, args) => { UpdateSelectedTab(); }; } public void ReplaceContainer(Decorator newBorder) { if (Object.ReferenceEquals(_border, newBorder)) return; _border.Child = null; // detach any tab content that old border may hold _border = newBorder; } public void UpdateSelectedTab() { _border.Child = GetCurrentContent(); } private ContentControl GetCurrentContent() { var item = _tabControl.SelectedItem; if (item == null) return null; var tabItem = _tabControl.ItemContainerGenerator.ContainerFromItem(item); if (tabItem == null) return null; var cachedContent = TabContent.GetInternalCachedContent(tabItem); if (cachedContent == null) { cachedContent = new ContentControl { DataContext = item, ContentTemplate = TabContent.GetTemplate(_tabControl), ContentTemplateSelector = TabContent.GetTemplateSelector(_tabControl) }; cachedContent.SetBinding(ContentControl.ContentProperty, new Binding()); TabContent.SetInternalCachedContent(tabItem, cachedContent); } return cachedContent; } } }

Ответ 3



Дополнение к ответу @VladD. Чтобы при старте приложения первая вкладка по умолчанию была выбрана, в MainWindow делаем установку Loaded += (s, e) => TabControlAbove.SelectedIndex = 0;. Также нужно обработать Ctrl+Click по содержимому вкладки, иначе будет срабатывать снятие выделения с текущего ListBoxItem и содержимое пропадет. Для этого вешаем на ListBox обработчик SelectionChanged="ListBox_SelectionChanged", в котором проверяем, что добавляемый элемент есть: private bool cancellingTabSelectionChange; private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (e.AddedItems.Count == 0 && !cancellingTabSelectionChange) { cancellingTabSelectionChange = true; ((ListBox)sender).SelectedItem = e.RemovedItems[0]; cancellingTabSelectionChange = false; } }

Добавление элементов при клике на данный блок

#javascript #svg #vuejs


Нужно сделать так, чтобы при клике по определённому блоку (100% на 100%, условно)
на месте клика появлялась SVG точка. 
    


Ответы

Ответ 1



Добавлять элементы на место клика можно так: var block = document.getElementById('block'); block.onclick = function(e) { var point = document.createElement('div'); point.className = 'point'; point.style.left = e.pageX + 'px'; point.style.top = e.pageY + 'px'; block.appendChild(point); } html, body { padding: 0px; margin: 0px; height: 100%; position: relative; } .block { width: 100%; height: 100%; position: absolute; left: 0px; top: 0px; } .block .point { position: absolute; width: 2px; height: 2px; background: #000; }


Ответ 2



Для реализации потребуется создать как минимум дочерний компонент, например: svg-point. Все точки из массива в родительском компоненте Vue перебираются через директиву v-for. В процессе перебора передаются необходимые данные компоненту svg-point. В качестве входящих параметров у этого компонента могут служить координаты XY. Сам же компонент отвечает только за визуальное отображение. Все действия по созданию/изменению/удалению точек происходят в родительском компоненте. При клике на родительский блок div необходимо проверять, не является ли элемент события click, унаследованным от SVGCircleElement, чтобы не размещать окружности друг над другом. В примере ниже все это реализовано: создание/редактирование/удаление. // Отключим ненужные для примера // сообщения в консоли. Vue.config.productionTip = false Vue.config.devtools = false const SvgPoint = { name: 'svg-point', props: { cx: Number, cy: Number }, computed: { // Для простоты задаём все атрибуты // ч/з вычисляемое свойство. pointStyle() { // Определим локально для удобства. // Критерием цвета послужит значение по оси Y. const criteria = this.$props.cy; // Цвет по умолчанию. let stroke = 'rgb(178, 214, 60)'; if (criteria > 300) { stroke = 'rgb(255, 121, 121)'; } else if (criteria > 150) { stroke = 'rgb(241, 196, 15)' } return { 'cx': this.$props.cx, // координата центра окружности по оси абсцисс 'cy': this.$props.cy, // координата центра окружности по оси ординат 'r': 1, // так как это точка, то радиус за единицу примем 'stroke': stroke, // цвет 'fill': 'transparent', // заливка роли не играет 'stroke-width': 8, // ..... чтобы точку видно было } } }, template: `` } new Vue({ el: '#app', // Локальная регистрация компонентов. components: { 'svg-point': SvgPoint }, data: { // Модель с точками. Добавим туда пару-тройку. points: [{ cx: 23, cy: 223 }, { cx: 118, cy: 280 }, { cx: 248, cy: 306.125 }, { cx: 341, cy: 261.125 }, { cx: 443, cy: 144.125 }, { cx: 508, cy: 26.125 }] }, methods: { // Обработка клика. clickHandler(event) { // event.stopPropagation(); // Определим локально для удобства // целевой объект клика. const target = event.target; // Если элемент, по которому кликнули - это точка: if (this.isCircle(target)) { // Отправляем на редактирование. // Индекс точки, взятый из атрибута `data-index`. return this.edit(target.dataset.index); } // Для подсчета координат точки. // Метод getBoundingClientRect() возвращает размер элемента и его позицию относительно `viewport`. // rectangle.left - слева; rectangle.top - сверху. // clientX - горизонтальная координата в пределах клиентской области приложения. // clientY - вертикальная координата в пределах клиентской области приложения. const rectangle = target.getBoundingClientRect(); // Сохраняем точку. this.save({ cx: event.clientX - rectangle.left, cy: event.clientY - rectangle.top }) }, // Обработка правого клика. removeHandler(event) { // event.stopPropagation(); // Определим локально для удобства. const target = event.target; // Если элемент, по которому кликнули - это точка: if (this.isCircle(target) && confirm('Удалить точку?')) { // Отправляем на удаление. // Индекс точки, взятый из атрибута `data-index`. return this.remove(target.dataset.index); } alert('Выберите точку для удаления!') }, // Сохранение точки. Просто добавляем в массив точек. save(data) { this.points.push({ cx: data.cx, cy: data.cy }) }, // Редактирование координат точки. edit(index) { // Найдем интересующую нас точку просто // по индексу из массива точек. const point = this.points[index]; const data = { // Сам в шоке, но почему бы и нет. cx: prompt('Укажите новую координату по оси абсцисс (x):', point.cx), cy: prompt('Укажите новую координату по оси ординат (y):', point.cy) } if (data.cx && data.cy) { // Отправляем на обновление. this.update(index, { // При ошибках в [0;0] отправляем. cx: parseFloat(data.cx), cy: parseFloat(data.cy) }) } }, // Обновление координат точки. update(index, data) { this.points.splice(index, 1, data); alert('Обновление точки'); }, // Удаление точки. remove(index) { this.points.splice(index, 1); alert('Удаление точки'); }, // Проверка объекта по принадлежности к классу. isCircle(element) { return element instanceof SVGCircleElement; }, // Экспорт в `.csv` файл. Без комментариев. exportToCsv(event) { let content = []; this.points.map(function(row) { content.push(Object.values(row).join(';')); }) // Заголовок и содержимое будущего файла. let csvContent = Object.keys(this.points[0]).join(';'); csvContent += "\r\n" + content.join("\r\n"); let url = URL.createObjectURL( new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }) ); event.target.setAttribute('href', url); event.target.setAttribute('download', '699135.csv'); } } }); *, *::after, *::before { box-sizing: border-box; } .points__boxs { margin: 0 auto; width: 600px; height: 400px; outline: 1px solid #08c; } .points__container { width: 100%; height: 100%; } circle:hover { r: 12px; }

Точкосоздаватель

  • ЛКМ - создание/редактирование точки.
  • ПКМ - удаление точки.
  • Экспорт файла .*csv по ссылке.
Дополнительно создан экспорт SVG точек в файл формата *.csv - разделителем служат ;.

изменение цвета svg при наведении

#html #css #svg #svg_спрайт


Столкнулся с проблемой, связанной с изменением цвета иконок svg. Придерживался этой
инструкции.

Есть спрайт svg и отдельный стилевой файл для него:

.icon {
  display: inline-block;
  width: 1em;
  height: 1em;
  fill: currentColor;
}

.icon-youtube {
  font-size:(13/10)*1rem;
  width:(15/13)*1em;
}


Подключаю на html через use:


    



оба варианта ниже не работают

.icon-youtube svg:hover { color: red; fill: red; }
.icon-youtube:hover { color: red; fill: red; } 


Проблема заключается в изменении цвета при наведении на иконку. Пробовал и fill,
и color. Ничего не работает.

Ресурс
3


а это точно svg? Подсказывают что это растор в обертке svg 
если это растор,то выходит цвет менять не получится,смысл тогда от такой svg
    


Ответы

Ответ 1



У SVG для покраски строки нужно применять атрибут - stroke:red; Ваше правило CSS должно быть таким : .icon-youtube svg:hover { stroke: red; fill: red; } .icon-youtube:hover { stroke: red; fill: red; }` Проверьте также и удалите, если они есть, атрибуты fill, stroke у иконок в спрайте, так как они имеют наивысший приоритет. Добавьте во внешнюю таблицу CSS принудительное наследование для атрибутов SVG: svg path { stroke:inherit; stroke-width:inherit; fill:inherit; } Это всё относится, конечно к чистому SVG, а у вас действительно растровая иконка встроенная векторным редактором в SVG. Выбирайте всегда SVG иконки, которые весят немного. Это верный признак того, что они сделаны профессионально,- патчами, а не лепкой, градиентами, маркерами в векторных редакторах. Один из полезных ресурсов для выбора SVG иконок Выше были теория, но практика всегда интересней? Скачал две иконки svg c ресурса iconmonstr: youtube - 1.8к; facebook - 0.3k 1. Пример закрашивания одной иконки при наведении svg path { fill:inherit; stroke:inherit; stroke-width:inherit; } .icon-youtube:hover { fill:red; } 2. Пример анимации закрашивания иконок Добавлен к первому примеру код второй иконки и анимация закрашивания при наведении: .icon-youtube{ transition: all .5s ease; } .icon-youtube:hover { fill:red; } svg path { fill:inherit; stroke:inherit; stroke-width:inherit; } .icon-youtube{ transition: all .8s ease; } .icon-youtube:hover { fill:red; } UPD Ещё пример, как добавлять социальные иконки и изменять цвет при наведении

Ответ 2



Необходимо перенести код svg на html страницу и подключать в ксс через fill. html:
  • css .button-futter:hover path, .button-futter:focus path{ fill: #000000;

    Ответ 3



    Надо поменять цвет по ховеру на родителе иконки: a.social__link svg.icon .social__link { color: red; &:hover { color: green; } }

    Ответ 4



    Добавьте :hover svg:hover * { fill: red; }

    Ответ 5



    Если по инструкции, то нужно через color .icon { &.icon-youtube { color:red; } }

    “javac” не является внутренней или внешней командой

    #java #javac

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


    Ответы

    Ответ 1



    Причина ошибки — заданы некорректные «переменные среды». Соответственно, необходимо указать правильные. На рабочем столе откройте «Этот компьютер»: Нажмите слева вверху «Свойства», затем слева в меню — «Дополнительные параметры системы». В открывшейся вкладке «Дополнительно» в самом низу выберите «Переменные среды». Откроется содержимое. Нажмите в каждом окне поочередно «Создать». В окне «Новая пользовательская переменная» пропишите CLASSPATH. Затем в окне «Новая системная переменная» укажите переменную PATH. В поле «Значение» пропишите директорию к пакету JDK. Перезагрузите Windows. Кроме того, чтобы выполнить Javac, вы можете в командной строке прописать полный путь к консоли. К примеру: C:\Program Files\Java\jdk1.8.0_102\bin\javac.exe" MyFile.java Источник

    Ответ 2



    Если не помогло, добавление в CLASSPATH, то добавь тот же самый путь в PATH, если там уже что-то есть то добавляй через точку с запятой ';'

    Ответ 3



    Если после добавления путей ничего не поменялось, то сделай копии папок jdk в Programm Files/java и Programm Files(x86)/java

    Ответ 4



    Небольшое дополнение, путь в переменных мы прописываем до папочки bin, иначе работать не будет. Пример: C:\Program Files\Java\jdk1.8.0_201\bin Перезагружаться скорее всего не понадобиться, но обязательно перезапустите командную строку.

    Ответ 5



    Надо перенести JAVA_HOME в самое начало переменной PATH, чтобы она была раньше стандартного пути, который прописался при установке: C:\Program Files (x86)\Common Files\Oracle\Java\javapath

    Обращение к 2 соседним элементам std::set

    #cpp #множества

    
    Возникла задача, в которой надо обращаться с двумя соседними элементами множества
    set. Такой вопрос: как это сделать? Гуглил, нигде не нашел информации по этому поводу,
    уже сомневаюсь, что так вообще можно делать. Например, у вектора этот вопрос решается
    так: v[i] - i-й элемент, а v[i+1] - соседний элемент. Можно ли делать что-то аналогичное
    во множестве? Метод find() не предлагать, так как я не знаю, какие числа лежат в контейнерах.
        
    


    Ответы

    Ответ 1



    Воспользуйтесь итераторами. Если итератор it указывает на нужный вам элемент set, например, найденный с помощью find() или, скажем, первый элемент, полученный с помощью begin(), то после выполнения ++it этот итератор будет указывать на следующий элемент контейнера.

    Как найти функцию обработки события onchange или другого события?

    #javascript

    
    
    
    Я хочу посмотреть как обрабатываются события нажатия кнопки.
    
    Каким образом мне можно найти эту функцию onchange="selmarshClick(this)"?
        
    


    Ответы

    Ответ 1



    Если нажать F12 в Chrome и зайти на вкладку Sources, то можно увидеть панель со вкладками, которые помогают при отладке. Одной из таких вкладок будет Event Listener Breakpoints, в которой можно назначить в качестве триггера любые события, при которых исполнение скрипта будет остановлено. Выбирай на вкус. В данном случае нужно будет выбрать Control → change Для Firefox нужно зайти в Инспектор, найти тот самый элемент, в котором прописано событие и обнаружить рядом значок em: Кликнув на него, как утверждает developer.mozilla.org/ru/docs можно увидеть строчки: где можно увидеть события, навешанные на элемент, скрипт, строку, возможность нажать на паузу и т.д. Если в Firefox нет кнопки паузы, как обещают, то можно попробовать посмотреть во вкладку Debugger(отладчик) и попробовать найти стрелку, при наведении на которую будет написано "Events". Там уже должно быть событие этого элемента. А вот таких полезных вкладок как у Chrome к сожалению у Firefox я не вижу.

    Как организовать взаимодействие объекта с его наблюдателем

    #c_sharp #net #шаблоны_проектирования

    
    Допустим у меня есть класс A. В классе А есть набор эвентов, которые отражают какие
    либо изменения внутри - изменения коллекций, изменение основных свойств/состояния.
    И у объекта есть свойство - объект класса B, который должен следить за этими состояниями
    и производить какую либо работу проанализировав набор всех изменений.
    
    Логично чтобы при создании объекта класса B, передавать ему в конструктор ссылку
    на объект класса A и привязываться к событиям.
    
    Интересует есть какие либо другие способы, реализации или паттерны.
        
    


    Ответы

    Ответ 1



    Интересует есть какие либо другие способы, реализации или паттерны В С# паттерн "наблюдатель" может быть реализован многими способами, например: На основе делегата На основе события При помощи строго типизированного интерфейса При помощи специальных интерфейсов IObserver/IObservable На основе делегата Решение на основе делегата предствляет собой классических колбек. Преимуществом данного метода является отсутствие явного, типизированного обработчика события (взаимоотношение между поставщиком и потребителем события никак не регламентируются) и простота метода – при возникновении события, метод класса Consumer вызывает аргумент-делегат: class Consumer { public void Event(Action callback) { ... callback(); } } При возникновении события будет вызван делегат act и весь его invocation list, таким образом поддерживается множественность обработки события. На основе события Метод похож на предыдущий, но с той разницей, что позволяет организовать подписку на события любому количеству обработчиков (без моделирования отношения 1:1 как в предыдущем методе) либо не иметь обработчиков вовсе. class Consumer { public event EventHandler Event; void RaiseEvent() { // Не самый потокобезопасный код if (Event != null) { Event.Invoke(this, new EventArgs()); } } } public class Program { public static void Main() { Consumer consumer = new Consumer(); consumer.Event += (object sender, EventArgs args) => { /* */ }; consumer.Event += (object sender, EventArgs args) => { /* */ }; } } Метод похож на предыдущий но не дает гарантий на присутствие хотя бы одного обработчика. При помощи строго типизированного интерфейса В этом методе потребитель обрабатывает события поставщика при помощи определенного интерфейса обработчика, строго формализуя отношения между поставщиком и потребителем. interface IEventHandler { void FirstEventHandler(); void SecondEventHandler(); } class Supplier : IEventHandler { public void FirstEventHandler() { /* Обработчик события */ } public void SecondEventHandler() { /* Обработчик другого события */ } } class Consumer { IEventHandler _supplier; public void Subscribe(IEventHandler supplier) { _supplier = supplier; } void RaiseFirstEvent() { _supplier.FirstEventHandler(); } void RaiseSecondEvent() { _supplier.SecondEventHandler(); } } public class Program { public static void Main() { Consumer consumer = new Consumer(); Supplier supplier = new Supplier(); consumer.Subscribe(supplier); } } Это почти классическая реализация паттерна подписчик в C# (и паттерна "делегат" в Objective-C с той лишь разницей, что все обработчики должны быть строго определены). Реализация этого метода требует пристального наблюдения на предмет нарушения SRP, так и согласованности событий поставщика. При помощи специальных интерфейсов IObserver/IObservable Начиная с .NET 4 доступны специальные интерфейсы IObserver/IObservable для реализации паттерна наблюдатель для последовательностей событий: class Data { } class Consumer : IObserver { public void OnCompleted() { } public void OnError(Exception e) { } public void OnNext(Data data) { // Обработка новых данных } } class Supplier : IObservable { List> _subscribers = new List>(); class Unsubscriber : IDisposable { private List>_observers; private IObserver _observer; public Unsubscriber(List> observers, IObserver observer) { _observers = observers; _observer = observer; } public void Dispose() { if (_observer != null && _observers.Contains(_observer)) _observers.Remove(_observer); } } public IDisposable Subscribe(IObserver observer) { _subscribers.Add(observer); return new Unsubscriber(_subscribers, observer); } void RaiseEvent() { foreach (var subscriber in _subscribers) { subscriber.OnNext(new Data()); } } } public class Program { public static void Main() { Consumer consumer = new Consumer(); Supplier supplier = new Supplier(); supplier.Subscribe(consumer); } }

    Ответ 2



    В "классическом" варианте паттерна "Наблюдатель" наблюдаемый субъект имеет методы: ЗарегистрироватьНаблюдателя(IНаблюдатель); УдалитьНаблюдателя(IНаблюдатель); ОповеститьНаблюдателей(); // этот приватный и имеются наблюдатели, которые реализуют некоторый интерфейс IНаблюдатель, который содержит метод Обновление(). Каждый наблюдатель содержит ссылку на наблюдаемый субъект и управляет подпиской/отпиской самостоятельно, либо получает ссылку в параметре метода Обновление(). По моему мнению, второй вариант предпочтительнее, так как первый "попахивает" наличием нескольких обязанностей, хотя могут быть и комбинации этих вариантов - например, наблюдатель содержит ссылку на наблюдаемый субъект, но подпиской не управляет и вообще ссылка эта публичная и извне ее можно заменить. Что касается C#: В C# присутствуют механизм событий, которые, по сути, и являются реализацией этого паттерна, поэтому наблюдаемому объекту специально ничего не нужно реализовывать, достаточно только выставить событие доступное для подписки и вызывать его при необходимости.

    Как переписать Template deduction guide (С++17) на C++14?

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

    
    Дан код на С++17: 
    
    template
    struct Ok {
        T value;
    };
    template<> struct Ok {};
    
    // template deduction guides
    template Ok(T) -> Ok;
    
    
    Template deduction guides позволяют имея тип Ok вызывать Ok как функцию (так выглядит,
    на самом деле вызывается конструктор):
    
    auto c = Ok(5); // T deduced as int
    // без template deduction guide я так писать не могу, 
    // но должен писать:
    auto c = Ok(5); // T can not be deduced :(
    
    
    Вопрос в том, как это переписать на С++14 или ниже? Чтоб я писал просто: 
    
    auto c = Ok("hello"s);  // T deduced as std::string
    
    
    Но с произвольным типом.
        
    


    Ответы

    Ответ 1



    template Ok> makeOk(T&& arg){ return Ok>{std::forward(arg)}; } auto c = makeOk(5); auto d = makeOk(std::make_unique(6.7));

    Ответ 2



    Начал писать как комментарий, но не уложился в границы. Ответ уже дан, но по большому счёту он был у Вас в вопросе, когда сравнивали конструктор с функцией. Классическое решение - это как раз использование шаблонных make- функций. Всякие make_pair, make_unique, make_shared яркие тому примеры. Дополнительно хочу заметить, что если тип Ok явно указывается только при создании (через функцию-конструктор), то можно зайти немного с другого конца, нежели это сделал Виктор Смирнов в своём ответе, и в качестве имени порождающей функции использовать Ok вместо makeOk. А саму структуру переименовать, скажем, в Ok_. Может быть таким образом получится уменьшить количество мест, требующих изменения кода.

    Что в приоритете: автоупаковка или автораспаковка?

    #java #autoboxing #unboxing

    
    public class Test {
        public static void main(String[] args) {
            Integer t = 1;
            int s = 1;
            System.out.println(s != t);  // (*)
        }
    }
    
    
    Вопрос: что делает компилятор со строкой (*)? Не понимаю, то ли распаковывает t,
    то ли упаковывает s...
    Мудрый человек, пишет что здесь идёт "autoboxing", но с ним мне не связаться и я
    не знаю почему он так пишет.
    Могу предположить только, что раз в сравнении у нас нашёлся Object some_obj, коим
    является Integer t, то идёт сравнение по ссылкам, и int s автоупаковывается.
    Из результатов программы: t==s -- правда. Не знаю почему так... Вроде потому, что
    есть какой-то метод, который для Integer, String и подобных им приводит объект к некоторому
    виду, заменяя ссылку на такой же по натуре объект, чтобы == работало. К примеру две
    "разных" строки, например: "Hello" и "Hello" после вызова этого метода в сравнении
    == дают true. 
    
    Итого: очень хочу увидеть какое-то документальное объяснение происходящего, что к
    чему приводится, и почему результат строки (*) есть false, что в принципе значит: t
    и s равны. Но в каком понимании они равны? Ссылок, чисел?... Байт-код мне не помог,
    там не понять как проходит это сравнение.
        
    


    Ответы

    Ответ 1



    Происходит распаковывание t (то есть преобразование из Integer в int) с последующим обычным сравнением примитивов (то есть значений типа int). Чтобы понять почему так происходит обратимся к спецификации Java. Описание оператора == и !=, JLS 15.21.1: If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2). Если операнды оператора сравнения оба имеют числовой тип, или один из операндов является числовым типом, а второй может быть преобразован в числовой тип, то операнды подвергаются binary numeric promotion. В случае сравнения int и Integer операнд типа int является примитивным типом, а операнд типа Integer может быть преобразован в числовой тип. В принципе не важно, как переводится binary numeric promotion, важно лишь что при этом выполняются действия описанные в соответствующем разделе JLS 5.6.2: If any operand is of a reference type, it is subjected to unboxing conversion (§5.1.8). Если один из операндов является ссылочным типом, то происходит распаковывание. В нашем случае распаковывается Integer и получается int. Далее обычным способом сравниваются два примитива (значения типа int).

    Ответ 2



    Легко проверяется экспериментально. Через использование кэша: https://ideone.com/sEhpKz import java.util.*; import java.lang.*; import java.io.*; class Ideone { public static void main (String[] args) throws java.lang.Exception { Integer a1 = 1, a1024 = 1024, b1 = 1, b1024 = 1024; if (a1 != b1 || a1024 == b1024) { System.out.println("Can't detect :("); } else if (a1024 == 1024 && b1024 == 1024) { System.out.println("Unboxing"); } else if (a1 == 1 && b1 == 1) { System.out.println("Boxing"); } else { System.out.println("Boxing without cache o_O"); } } } Через исключение при unboxing'е null'а: https://ideone.com/ltbefI import java.util.*; import java.lang.*; import java.io.*; class Ideone { public static void main (String[] args) throws java.lang.Exception { Integer a = null; try { boolean ignored = a == 1; } catch (NullPointerException ex) { System.out.println("Unboxing"); return; } System.out.println("Boxing"); } } В обоих случаях выводится: Unboxing

    Как удалить читера из таблицы рекордов Google Play Services?

    #android #google_play_services

    
    Я столкнулся с такой проблемой: мою игру взломали на рекорд и он зачёлся в таблице
    как лучший. Вопрос следующий: как можно удалить фальшивый счёт в таблице рекордов leaderboard?
        
    


    Ответы

    Ответ 1



    Решение которое помогло мне скрыть читера из таблицы рекордов: Переходим на сервис гугла OAuth 2.0 Playground. В правом верхнем углу нажимаем настройки. В выпавшем окошке внизу устанавливаем галочку Use your own OAuth credentials. В полях OAuth Client ID и OAuth Client secret вставляем значения идентификатора OAuth 2.0 Вашего приложения. Получить его можно в Google APIs в разделе Учётные данные. В списке слева надо найти Google Play Game Service. Либо ввести https://www.googleapis.com/auth/games в поле ниже. На втором шагу получаем токены доступа. Для начала нам надо узнать playerId игрока, которого Вы хотите скрыть из таблицы рекордов. Для этого отправляем Get запрос: https://www.googleapis.com/games/v1/leaderboards/LEADERBOARD_ID/scores/PUBLIC?timeSpan=ALL_TIME LEADERBOARD_ID - Ваш ID таблицы рекордов. Подробнее об этом запросе можно узнать здесь. Выделив нужный playerId, отправляем POST запрос на скрытие игрока: https://www.googleapis.com/games/v1management/applications/ID_APPLICATION/players/hidden/PLAYER_ID/ ID_APPLICATION - Номер вашего приложения. Получить его можно в Google Play Console. Как правило это 11 цифр. PLAYER_ID - ID игрока которого надо скрыть. Подробнее об этом запросе можно узнать здесь. Проверяем таблицу рекордов в игре. Если на 3 этапе у Вас появилась ошибка There is no linked app associated with this client ID, то Вам необходимо в Google Play Console связать приложение как Web приложение. Как это сделать можно узнать здесь.

    Получение индекса первого not null элемента массива

    #java

    
    Есть какой-нибудь красивый способ получения индекса первого not null элемента массива?
    Да, можно написать
    
    int index;
    for (int i = 0; i < arr.length; i++) {
       if (arr[i] != null) {
           index = i;
           break;
       }
    }
    
    
    но, может, есть какой-нибудь более красивый способ для этого? Например, для получения
    первого not null элемента массива есть метод ObjectUtils.firstNonNull, может, есть
    что-то похожее и для получения индекса?
        
    


    Ответы

    Ответ 1



    Можно написать цикл чуть короче: int index = 0; while (index < arr.length && arr[index] == null) ++index; Или даже: int index = -1; while (++index < arr.length && arr[index] == null) {} Или вот вариант с for (спасибо @Qwertiy!): int index; for (index = 0; index < arr.length && arr[index] == null; ++index); Также можно написать свой метод для этого, использующий любой из способов выше, либо вот так (Ideone): static int firstNotNullIndex(T[] arr) { for (int i = 0; i < arr.length; ++i) if (arr[i] != null) return i; // или `return -1` return arr.length; }

    Ответ 2



    Может так (java 8, для String)?: Arrays.asList(array).indexOf(Arrays.stream(array).filter(Objects::nonNull).findFirst().get())

    Ответ 3



    По-моему, вот самое изящное решение (благодаря помощи англоязычного SO): int titleIndex = IntStream.range(0, arr.length) .filter(i -> arr[i] != null) .findFirst().getAsInt();

    Различие между subscribeOn и observeOn методами

    #rxjava

    
    В чём заключается различие между subscribeOn и observeOn методами?
    
    Правильно ли я его понимаю? 
    
    Вот то, как я это понимаю: subscribeOn определяет поток по умолчанию для Observable
    после его создания (в случае, если его нужно выполнять не в текущем потоке), т.о.,
    начинаться выполнение будет всегда в потоке, определённом subscribeOn. И поэтому subscribeOn
    нужен только один (если будет несколько subscribeOn, выполнится только первый). А observeOn
    после может поменять поток, начиная с места вызова, и сколько будет observeOn, столько
    раз будет меняться поток.
        
    


    Ответы

    Ответ 1



    Нашла полезную статью, которая содержит точный ответ насчёт количества и места вызова данных методов. Надеюсь, поможет кому-нибудь ещё. По поводу subscribeOn() The subscribeOn() operator will have the same effect no matter where you place it in the observable chain; however, you can't use multiple subscribeOn() operators in the same chain. If you do include more than one subscribeOn(), then your chain will only use the subscribeOn() that’s the closest to the source observable. Что значит: Оператор subscribeOn() будет иметь тот же эффект независимо от того, где вы поместите его в цепочку observable; однако вы не можете использовать несколько операторов subscribeOn() в одной цепочке. Если вы включили в цепочку более одного subscribeOn(), ваша цепочка будет использовать только subscribeOn(), который ближе всего к observable источнику. subscribeOn(), который ближе всего к Observable источнику - это первый в цепочке, и данное утверждение было также проверено опытным путём, например, если есть цепочка: observable .subscribeOn(Schedulers.newThread()) .subscribeOn(Schedulers.computation()) .subscribe(observer); то onNext() каждого элемента выполняется в потоке RxNewThreadScheduler-1 (потоке, созданном Schedulers.newThread()), а цепочка observable .subscribeOn(Schedulers.computation()) .subscribeOn(Schedulers.newThread()) .subscribe(observer); передаёт выполнение onNext() каждого элемента в поток RxComputationThreadPool-1 (поток, созданном Schedulers.computation()). По поводу observeOn() Unlike subscribeOn(), where you place observeOn() in your chain does matter, as this operator only changes the thread that’s used by the observables that appear downstream. For example, if you inserted the following into your chain then every observable that appears in the chain from this point onwards will use the new thread. .observeOn(Schedulers.newThread()) This chain will continue to run on the new thread until it encounters another observeOn() operator, at which point it’ll switch to the thread specified by that operator. You can control the thread where specific observables send their notifications by inserting multiple observeOn() operators into your chain. Что значит: В отличие от subscribeOn(), имеет значение, куда в цепочку вы помещаете функцию observeOn(), так как этот оператор только изменяет поток, который используется observables, которые следуют ниже. Например, если вы вставляете в свою цепочку следующий код, то каждый observable, который появляется в цепочке с этого момента, будет использовать новый поток. .observeOn(Schedulers.newThread()) Эта цепочка будет продолжать работать в новом потоке, пока не встретится другой оператор observOn(), после чего она переключится на поток, указанный этим оператором. Вы можете управлять потоком, куда конкретные observables отправляют свои уведомления, путём вставки в вашу цепочку нескольких операторов observeOn().

    Разбить “класс-бог”

    #c_sharp #wcf

    
    В моём проекте есть сервис WCF, есть интерфейс описывающий ServiceContract (IMainHost),
    и есть класс на основе этого интерфейса (MainHost). И всё отлично работает. Смущает
    только одно - класс такого размера что студия тормозит когда я его редактирую. Создавать
    ещё один сервис так себе вариант. Я его конечно могу сделать partial, но вдруг есть
    какие то другие варианты? 
        
    


    Ответы

    Ответ 1



    Делегирование (англ. Delegation) — основной шаблон проектирования, в котором объект внешне выражает некоторое поведение, но в реальности передаёт ответственность за выполнение этого поведения связанному объекту. Часть внутренней реализации MainHost вынести по смыслу в отдельные классы и использовать их внутри MainHost.

    Ответ 2



    Методы wcf-сервиса должны представлять собой всего несколько строк: [АтрибутДляКонтроляПравДоступа(какие, то, параметры)] public Метод(Его аргументы) { return КакойТоBll.Метод(аргументы); } Итого 6 строк (одна пустая) на метод. Остальное следует разложить по bll-классам.

    Как чекнуть другую радиокнопку, если определенная уже чекнута

    #javascript #html

    
    
    
    
    как написать условие если радиокнопка с name="option" id="radio2" чекнута, то чекнуть name="anothername" с id="radio4" тоже


    Ответы

    Ответ 1



    /*хватаем элемент по id вешаем на него обработчик события change*/ document.getElementById('radio2').addEventListener('change', function() { /*и тут проверяем, если данный эл checked*/ if (document.getElementById('radio2').checked) { /*выполняем действия присваиваем radio4 checked = true*/ document.getElementById('radio4').checked = true; /*добавляем атрибут checked по просьбе из комментария*/ document.getElementById('radio4').setAttribute('checked', 'checked'); } })


    Ответ 2



    В jquery есть метод is. С его помощью определяем check or uncheck кнопки. А после этого методом prop изменяем check другого radio кнопки. $(document).ready(function(){ $('#radio2').change(function(event){ if($(this).is(':checked')){ $( "#radio4" ).prop( "checked", true ); //После того как мы сделали `check` Второй радио кнопки давайте сделаем лог. console.log($( "#radio4" ).is(':checked')); } }); });


    Автодополнение в пользовательских программах

    #bash #autocomplete

    
    В Linux-е когда через bash запускаешь какую-то программу, то можно используя Tab
    ускорять ввод параметров, которые нужно передать этой программе. Как сделать так, чтобы
    автодополнение работало и в моей программе?
        
    


    Ответы

    Ответ 1



    микропример. сделаем для нашей (пока несуществующей) программы автодополнение опций -a, -b и параметра c : $ complete -W "-a -b c" x проверяем. вводим x, затем пробел, затем символ tab дважды и видим предложенные варианты: $ x -a -b c чтобы это работало в каждой сессии, команду (complete ...) можно добавить в конец файла ~/.bashrc. чтобы выполнялось автодополнение именами файлов/каталогов, можно, к примеру, добавить команде complete опцию -f: $ complete -f -W "-a -b c" x а дальше уже надо читать документацию (https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html) и смотреть на примеры (с актуальными версиями пакета bash/bash-completion — в каталоге /usr/share/bash-completion/completions/)

    Ответ 2



    как вариант можете посмотреть примеры в директории /etc/bash_completion.d/* В 16 UBUNTU autocomplete программ расположены в директории /usr/share/bash-completion/completions/ Более подробно тут

    Вопрос про stream api java 8

    #java #lambda #java_8 #java_stream

    
    Здравствуйте, имеется 2 стринговых листа List fileList и List arr,
    требуется вывести сколько слов в fileList содержатся в arr, сделал так:
    
    fileList
            .stream()
            .filter(s -> arr
                            .stream()
                            .anyMatch(s::equals)
            )
            .count()
    
    
    Правильный ли такой подход? Или есть какой-то более лучший способ?
        
    


    Ответы

    Ответ 1



    Быстрее и проще будет воспользоваться пересечением множеств: Set set = new HashSet<>(fileList); set.retainAll(new HashSet(arr)); int count = set.size(); А если уж использовать стримы, то не плодить их для каждого элемента. Эффективнее будет так: long count = fileList.stream() .filter(arr::contains) .count();

    Возможен ли breakpoint на определённых данных в Idea?

    #java #intellij_idea #breakpoint

    
    Интересует вопрос о том, возможно ли сделать так, чтобы брейкпоинты срабатывали только
    на определённом участке кода, при прохождении определённых данных? К примеру, есть
    лист с пятью миллионами элементов, каждая итерация вызывает стороннюю функцию к элементу,
    мне нужно, чтобы брейкпоинт сработал, к примеру, на 4-ых тысячном элементе, чтобы не
    пробегать по всем. Актуально для Intellij Idea 2016.
        
    


    Ответы

    Ответ 1



    Правый клик по breakpoint, в поле Condition напишите нужное вам условие (напр. i == 400). Для открытия более детальной настройки ваших breakpoints: Ctrl+Shift+F8 - Windows ⇧⌘F8 - Mac

    Определение максимального значения выражения (анти-сортировка)

    #cpp #алгоритм

    
    Дано число n. Далее задана последовательность n чисел. Определить 
    максимальное значение этого выражения: 
    
    
      |M1 - M2| + |M2 - M3| + ... + |Mn-1 - Mn|.
    
    
    Пример:  
    
    
      Ввод:  5 1 3 5 7 9
      
      Вывод: 22  
      
      Максимальное значение 22, так как:  
      
      |3 - 9| + |9 - 1| + |1 - 7| + |7 - 5| = 22
    
    
    Мой пример решения  (иногда выдает не правильный ответ) 
    
    Идея решения : Сначала я упорядочил массив методом пузырька.
    Всего пар  ( |M1 - M2| , |M2 - M3|, ... , |Mn-1 + Mn| ) будет n-1. Если в выражении
    раскрыть модуль, то: 
    
    Если a >= b : |a - b| = a - b
    Если a < b : |a - b| = b - a.
    
    То есть возле каждого числа стоит + или -. Их равное количество и равняется n-1.
    Каждое число используется в выражении дважды (кроме первого и последнего (M1, Mn)
    ). Чтобы сумма вышла максимальной возле больших чисел ставил +, возле меньших -.
    
    #include 
    #include 
    using namespace std;
    
    int main()
    {
      int n,plus,minus;
      cin>>n;
      double s = n;
      plus = n-1;
      minus=n-1;
      int sum = 0;
      int arr[n];
      for(int i = 0; i < n; i++)
          {
              cin>>arr[i];
          }
      for(int i = 0; i < n-1; i++)
          {
              for(int j = 0; j < n-i-1; j++)
                  {
                      if(arr[j]>arr[j+1])
                      swap(arr[j],arr[j+1]);
                  }
          }
    
          for(int i = 0; i < n-round((s-1)/2+0.1); i++)
              {
                  sum-=arr[i];
                  minus--;
              }
    
    
          for(int i = 0; i < n; i++)
              {
                  if(minus>0)
                  {
                      sum-=arr[i];
                      minus--;
                  }
    
                  if(minus>0)
                  {
                      sum-=arr[i];
                      minus--;
                  }
              }
              for(int i = n-1; i >=0; i--)
              {
                  if(plus>0)
                  {
                      sum +=arr[i];
                      plus--;
                  }
    
                  if(plus>0)
                  {
                      sum +=arr[i];
                      plus--;
                  }
              }
    
              cout<


    Ответы

    Ответ 1



    "Жадный" алгоритм, уверенности в оптимальности которого пока нет: Сортируем значения по возрастанию       M1, M2, ..., Mn Обходим ("прыгаем") значения в порядке туда-сюда снаружи-к-центру:       M1, Mn, M2, Mn-1, M3, Mn-2...   пока не придем в последнюю вершину M[n/2] Из нее "прыгаем" в M1, тем самым замыкая цикл Из полученного цикла обхода вершин удаляем самое короткое ребро, т.е. ребро (i, j) с минимальным значением |Mi-Mj|. Это будет либо последний прыжок с шага 2, либо прыжок с шага 3 Оставшаяся цепь дает максимальную сумму (предположительно) Однако алгоритм пока не верен. Если следовать той же самой интуиции, то нам надо попробовать те же самые "прыжки", но начиная с последнего элемента массива. Например, на входе { 2, 4, 5, 7, 9 } вышеприведенный алгоритм даст |5 - 2| + |2 - 9| + |9 - 4| + |4 - 7| = 18 в то время как начиная "прыжки" с последнего элемента мы можем получить |5 - 9| + |9 - 2| + |2 - 7| + |7 - 4| = 19 Другими словами, рассмотреть вышеприведенным алгоритмом следует как отсортированный по возрастанию набор чисел, так и отсортированный по убыванию. Есть подозрение, что рассмотрев оба варианта и выбрав лучший из двух, мы все таки найдем максимум. (Интуиция и эксперимент подсказывают, что такое явление может наблюдаться только на наборах с нечетным количеством элементов. Это, по-идее, должно быть несложно доказать. Также, в случае нечетного количества элементов скорее всего есть критерий, позволяющий заранее увидеть, какой из двух вариантов лучше, не прогоняя всего алгоритма. Но пока, на всякий случай, будем честно проверять оба варианта всегда.) Интенсивное тестирование в сравнении с переборным алгоритмом пока не выявило нарушений. #include #include #include #include int max_sum(const int a[], int n) { int w_sum = 0; int j_last = n / 2, i_last = j_last + (n % 2 == 0 ? -1 : +1); int w_last = std::abs(a[j_last] - a[i_last]), w_closing = std::abs(a[j_last] - a[0]); bool plus = false; if (w_closing > w_last) { std::cout << "|" << a[j_last] << " - " << a[0] << "|"; w_sum += w_closing; plus = true; } for (int i = 0, step = n - 1, j = i + step; j != j_last; i = j, step = -step - (step < 0) + (step > 0), j = i + step) { std::cout << (plus ? " + " : "") << "|" << a[i] << " - " << a[j] << "|"; w_sum += std::abs(a[j] - a[i]); plus = true; } if (w_closing <= w_last) { std::cout << (plus ? " + " : "") << "|" << a[i_last] << " - " << a[j_last] << "|"; w_sum += w_last; } std::cout << " = " << w_sum << std::endl; return w_sum; } int main() { int a[] = { 2, 4, 5, 7, 9 }; int n = std::size(a); std::sort(a, a + n); int sum1 = max_sum(a, n); std::reverse(a, a + n); int sum2 = max_sum(a, n); std::cout << "Best = " << std::max(sum1, sum2) << std::endl; }

    Ответ 2



    ЧАСТНЫЕ СЛУЧАИ В частных случаях решение можно получить перебором всех возможных комбинаций. Программа (C#): public static int[] FactGen(int n) { int[] fact = new int[n + 1]; fact[0] = 1; for (int i = 1; i < n + 1; i++) fact[i] = i * fact[i - 1]; return fact; } public static int[] PermsGenerator(int[] arr, int num, int[] fact) { int i, j, f, newind, newnum, newval, size = arr.Length; int[] result = new int[size]; Array.Copy(arr, result, size); for (i = 0, newnum = num; i < size - 1; i++) { newind = newnum / (f = fact[size - 1 - i]); newnum = newnum - newind * f; newval = result[i + newind]; for (j = i + newind; j > i; j--) result[j] = result[j - 1]; result[i] = newval; } return result; } public static int SumAbs(int[] arr) { int sum = 0, prev = arr[0]; foreach (int value in arr) { sum += Math.Abs(value - prev); prev = value; } return sum; } public static int[] MaxArr(int[] arr, bool detprn) { int i, j, sum, smax = -1, size = arr.Length; int[] perm, result = new int[size], fact = FactGen(size), sorted = new int[size], empire = new int[size]; Array.Copy(arr, sorted, size); Array.Sort(sorted); for (i = 0; i < fact[size]; i++) { if ((sum = SumAbs(perm = PermsGenerator(sorted, i, fact))) > smax) { smax = sum; result = perm; } if (detprn) { Console.Write("\nПерестановка: "); foreach (int value in perm) Console.Write(value + " "); Console.Write(" Сумма: {0} Максимальная сумма: {1}", sum, smax); } } Console.Write("\nИсходная выборка: "); foreach (int value in arr) Console.Write(value + " "); Console.Write("\nОтсортированная выборка: "); foreach (int value in sorted) Console.Write(value + " "); Console.Write("\nЛучшая перестановка: "); foreach (int value in result) Console.Write(value + " "); Console.WriteLine("\nМаксимальная сумма: {0}", smax); empire[0] = sorted[i = size / 2 - 1]; empire[1] = sorted[i + 2]; empire[size - 1] = sorted[i + 1]; for (i = 2, j = 0; i < size - 1; i++, j = (size) - 1 + ((i + 1) & 1) - j) empire[i] = sorted[j]; Console.Write("Эвристический алгоритм: "); foreach (int value in empire) Console.Write(value + " "); Console.WriteLine("\nСумма: {0}", SumAbs(empire)); return result; } static void Main(string[] args) { bool binc; int i, j, n, nmax = 10; int[] arr; Random rand = new Random(); MaxArr(new int[] { 1, 2, 3, 4 }, false); MaxArr(new int[] { 1, 2, 3, 4, 5 }, false); for (n = 6; n < nmax + 1; n++) { arr = new int[n]; for (i = 0; i < n;) { arr[i] = rand.Next(1, 5 * n); binc = true; for (j = 0; j < i; j++) binc &= (arr[i] != arr[j]); if (binc) i++; } MaxArr(arr, false); } } Результаты: Исходная выборка: 1 2 3 4 Отсортированная выборка: 1 2 3 4 Лучшая перестановка: 2 4 1 3 Максимальная сумма: 7 Эвристический алгоритм: 2 4 1 3 Сумма: 7 Исходная выборка: 1 2 3 4 5 Отсортированная выборка: 1 2 3 4 5 Лучшая перестановка: 2 4 1 5 3 Максимальная сумма: 11 Эвристический алгоритм: 2 4 1 5 3 Сумма: 11 Исходная выборка: 26 10 21 4 27 5 Отсортированная выборка: 4 5 10 21 26 27 Лучшая перестановка: 10 26 4 27 5 21 Максимальная сумма: 99 Эвристический алгоритм: 10 26 4 27 5 21 Сумма: 99 Исходная выборка: 34 3 32 16 28 27 26 Отсортированная выборка: 3 16 26 27 28 32 34 Лучшая перестановка: 26 28 3 32 16 34 27 Максимальная сумма: 97 Эвристический алгоритм: 26 28 3 34 16 32 27 Сумма: 97 Исходная выборка: 27 3 34 38 18 29 31 39 Отсортированная выборка: 3 18 27 29 31 34 38 39 Лучшая перестановка: 29 34 3 38 18 39 27 31 Максимальная сумма: 128 Эвристический алгоритм: 29 34 3 39 18 38 27 31 Сумма: 128 Исходная выборка: 40 27 4 9 32 35 41 39 2 Отсортированная выборка: 2 4 9 27 32 35 39 40 41 Лучшая перестановка: 32 2 39 4 40 9 41 27 35 Максимальная сумма: 223 Эвристический алгоритм: 27 35 2 41 4 40 9 39 32 Сумма: 221 Исходная выборка: 41 35 45 27 34 33 18 24 16 25 Отсортированная выборка: 16 18 24 25 27 33 34 35 41 45 Лучшая перестановка: 27 34 16 35 18 41 24 45 25 33 Максимальная сумма: 150 Эвристический алгоритм: 27 34 16 45 18 41 24 35 25 33 Сумма: 150 Таким образом: Нашлась более удачная комбинация для исходного массива. Контрпример для эвристического алгоритма нашёлся не сразу. ОБЩЕЕ РЕШЕНИЕ (10.02.2018) Пусть a = {a0 = M1, a1 = M2, …, an-2 = Mn-1, an-1 = Mn} - исходная последовательность, b = {b0, b1, …, bn-2, bn-1} -та же последовательность в порядке возрастания, с = {c0, c1, …, cn-2, cn-1} -требуемая последовательность. Рассмотрим по отдельности случаи чётного и нечётного n. Случай n = 2k S(a) = Sц(a) - |an-1 - a0|, где Sцa) = |a0 - a1| + |a1 - a2| + … + |an-3 - an-2| + |an-2 - an-1| + |an-1 - a0|. Sц(a) - это алгебраическая сумма, которая содержит каждый исходный элемент ai дважды, и её максимальное значение равно Sц_max = 2∑i = 0, …, k-1 (hi - bi), где hi = bi+k, i = 0…k-1. Это значение достигается в двух вариантах перестановок: 1) c2i ∈ h (все наибольшие элементы имеют чётные индексы); 2) c2i + 1 ∈ h (все наибольшие элементы имеют нечётные индексы). В то же время, минимум |an-1 - a0| = bk - bk-1 достигается при размещении пары медианных элементов на краях последовательности c. Максимум суммы S равен Smax = 2∑i = 0, …, k-2 (bi+k - bi) + bk-1 - bk, или Smax = 2∑i = 0, …, k-2 (bn-1-i - bi) + bn-k - bk-1, и достигается в тех случаях, когда последовательность с содержит наибольшие элементы в шахматном порядке, причём медианные элементы bk-1 и bk находятся на краях последовательности. Количество таких перестановок при попарно различных ai составляет 2(k-1)!2. Случай n = 2k+1 Аналогичное рассмотрение показывает, что максимум S равен Smax = 2∑i=0…k-2 (bk+2+i - bk) + bk+1 - bk-1 + max (bk+1 - bk, bk - bk-1), или Smax = 2∑i=0…k-2 (bn-1-i - bi) + bn-k - bk-1 + max (bk+1 - bk, bk - bk-1), и достигается в тех случаях, когда элементы с индексами больше k идут в шахматном порядке, а на краях последовательности оказываются медианный и ближайший к нему элемент. Количество таких перестановок при попарно различных ai не меньше, чем (k-1)!k! (если медиана отличается от ближайших по значению соседей на одинаковую величину, то перестановок вдвое больше). ПРОГРАММА (C#): public static void T(string text, Stopwatch timer) { TimeSpan ts = timer.Elapsed; string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10); Console.Write(text + elapsedTime); } public static int[] FactGen(int n) { int[] fact = new int[n + 1]; fact[0] = 1; for (int i = 1; i < n + 1; i++) fact[i] = i * fact[i - 1]; return fact; } public static int[] PermsGenerator(int[] arr, int num, int[] fact) { int i, j, f, newind, newnum, newval, size = arr.Length; int[] result = new int[size]; Array.Copy(arr, result, size); for (i = 0, newnum = num; i < size - 1; i++) { f = fact[size - 1 - i]; newind = i; while (newnum >= f) { newind++; newnum -= f; } newval = result[newind]; for (j = newind; j > i; j--) result[j] = result[j - 1]; result[i] = newval; } return result; } public static int SumAbs(int[] arr) { int sum = 0, prev = arr[0]; foreach (int value in arr) { sum += Math.Abs(value - prev); prev = value; } return sum; } public static int CalcOptQuant (int n) { int k = (n - 1) / 2, k2 = Math.Max(k-2, 0); int[] fact = FactGen(k + 2); return 2*fact[k] * ((n - k - k < 2) ? fact[k-1] : fact[k]); } public static int CalcMaxSum(int[] brr) { int i, size = brr.Length, k = size / 2, sum = 0; for (i = 0; i < k - 1; i++) sum += brr[size - 1 - i] - brr[i]; sum = 2 * sum + brr[size - k] - brr[k - 1]; if (size - 2 * k > 0) sum += Math.Max(brr[k+1] - brr[k], brr[k] - brr[k-1]); return sum; } public static int[] MaxArr(int[] arr, bool detprn) { int i, j, sum, smax = -1, size = arr.Length; int[] perm, result = new int[size], fact = FactGen(size), sorted = new int[size], empire = new int[size]; Stopwatch sw = new Stopwatch(); Console.WriteLine("\nИсходная выборка: "); foreach (int value in arr) Console.Write(value + " "); sw.Restart(); for (i = 0; i < fact[size]; i++) { perm = PermsGenerator(arr, i, fact); sum = SumAbs(perm); if (sum > smax) { smax = sum; result = perm; } } if (detprn) Console.Write("\nЛучшие перестановки"); for (i = 0, j = 0; i < fact[size]; i++) { perm = PermsGenerator(arr, i, fact); sum = SumAbs(perm); if (sum == smax) { j++; if (detprn) { Console.Write("\n#{0}: ", j); foreach (int value in perm) Console.Write(value + " "); } } } Array.Copy(arr, sorted, size); Array.Sort(sorted); Console.WriteLine("\nОтсортированная выборка: "); foreach (int value in sorted) Console.Write(value + " "); Console.Write("\nФакт Наибольшая сумма: {0} Лучших перестановок: {1}" + "\nРасчёт Наибольшая сумма: {2} Лучших перестановок, не менее: {3}", smax, j, CalcMaxSum(sorted), CalcOptQuant(size)); T("\nRuntime = ", sw); sw.Reset(); return result; } static void Main(string[] args) { bool binc; int i, j, n, nmax = 12; int[] arr = new int[0]; Random rand = new Random(); MaxArr(new int[] { 0, 1, 2, 3, 4, 5 }, true); MaxArr(new int[] { 5, 1, 3, 5, 7, 9 }, true); MaxArr(new int[] { 0, 1, 2, 3, 4 }, true); MaxArr(new int[] { 0, 1, 2, 3 }, true); MaxArr(new int[] { 0, 1, 2 }, true); for (n = 3; n <= nmax; n++) { Array.Resize(ref arr, n); for (i = 0; i < n;) { arr[i] = rand.Next(10, 99); binc = true; for (j = 0; j < i; j++) binc &= (arr[i] != arr[j]); if (binc) i++; } MaxArr(arr, false); } } РЕЗУЛЬТАТЫ: Исходная выборка: 0 1 2 3 4 5 Лучшие перестановки #1: 2 4 0 5 1 3 #2: 2 4 1 5 0 3 #3: 2 5 0 4 1 3 #4: 2 5 1 4 0 3 #5: 3 0 4 1 5 2 #6: 3 0 5 1 4 2 #7: 3 1 4 0 5 2 #8: 3 1 5 0 4 2 Отсортированная выборка: 0 1 2 3 4 5 Факт Наибольшая сумма: 17 Лучших перестановок: 8 Расчёт Наибольшая сумма: 17 Лучших перестановок, не менее: 8 Runtime = 00:00:00.01 Исходная выборка: 5 1 3 5 7 9 Лучшие перестановки #1: 5 1 7 3 9 5 #2: 5 1 9 3 7 5 #3: 5 3 7 1 9 5 #4: 5 3 9 1 7 5 #5: 5 7 1 9 3 5 #6: 5 7 3 9 1 5 #7: 5 9 1 7 3 5 #8: 5 9 3 7 1 5 #9: 5 1 7 3 9 5 #10: 5 1 9 3 7 5 #11: 5 3 7 1 9 5 #12: 5 3 9 1 7 5 #13: 5 7 1 9 3 5 #14: 5 7 3 9 1 5 #15: 5 9 1 7 3 5 #16: 5 9 3 7 1 5 Отсортированная выборка: 1 3 5 5 7 9 Факт Наибольшая сумма: 24 Лучших перестановок: 16 Расчёт Наибольшая сумма: 24 Лучших перестановок, не менее: 8 Runtime = 00:00:00.01 Исходная выборка: 0 1 2 3 4 Лучшие перестановки #1: 1 3 0 4 2 #2: 1 4 0 3 2 #3: 2 0 4 1 3 #4: 2 1 4 0 3 #5: 2 3 0 4 1 #6: 2 4 0 3 1 #7: 3 0 4 1 2 #8: 3 1 4 0 2 Отсортированная выборка: 0 1 2 3 4 Факт Наибольшая сумма: 11 Лучших перестановок: 8 Расчёт Наибольшая сумма: 11 Лучших перестановок, не менее: 4 Runtime = 00:00:00.01 Исходная выборка: 0 1 2 3 Лучшие перестановки #1: 1 3 0 2 #2: 2 0 3 1 Отсортированная выборка: 0 1 2 3 Факт Наибольшая сумма: 7 Лучших перестановок: 2 Расчёт Наибольшая сумма: 7 Лучших перестановок, не менее: 2 Runtime = 00:00:00.00 Исходная выборка: 0 1 2 Лучшие перестановки #1: 0 2 1 #2: 1 0 2 #3: 1 2 0 #4: 2 0 1 Отсортированная выборка: 0 1 2 Факт Наибольшая сумма: 3 Лучших перестановок: 4 Расчёт Наибольшая сумма: 3 Лучших перестановок, не менее: 2 Runtime = 00:00:00.01 Исходная выборка: 25 51 87 Отсортированная выборка: 25 51 87 Факт Наибольшая сумма: 98 Лучших перестановок: 2 Расчёт Наибольшая сумма: 98 Лучших перестановок, не менее: 2 Runtime = 00:00:00.00 Исходная выборка: 78 10 34 64 Отсортированная выборка: 10 34 64 78 Факт Наибольшая сумма: 166 Лучших перестановок: 2 Расчёт Наибольшая сумма: 166 Лучших перестановок, не менее: 2 Runtime = 00:00:00.00 Исходная выборка: 23 26 93 16 45 Отсортированная выборка: 16 23 26 45 93 Факт Наибольшая сумма: 195 Лучших перестановок: 4 Расчёт Наибольшая сумма: 195 Лучших перестановок, не менее: 4 Runtime = 00:00:00.00 Исходная выборка: 85 12 11 13 90 88 Отсортированная выборка: 11 12 13 85 88 90 Факт Наибольшая сумма: 382 Лучших перестановок: 8 Расчёт Наибольшая сумма: 382 Лучших перестановок, не менее: 8 Runtime = 00:00:00.00 Исходная выборка: 82 43 28 55 29 39 18 Отсортированная выборка: 18 28 29 39 43 55 82 Факт Наибольшая сумма: 206 Лучших перестановок: 24 Расчёт Наибольшая сумма: 206 Лучших перестановок, не менее: 24 Runtime = 00:00:00.00 Исходная выборка: 64 20 43 89 47 94 52 71 Отсортированная выборка: 20 43 47 52 64 71 89 94 Факт Наибольшая сумма: 300 Лучших перестановок: 72 Расчёт Наибольшая сумма: 300 Лучших перестановок, не менее: 72 Runtime = 00:00:00.02 Исходная выборка: 45 53 81 17 76 97 26 50 51 Отсортированная выборка: 17 26 45 50 51 53 76 81 97 Факт Наибольшая сумма: 337 Лучших перестановок: 288 Расчёт Наибольшая сумма: 337 Лучших перестановок, не менее: 288 Runtime = 00:00:00.23 Исходная выборка: 55 51 36 12 82 63 89 58 14 22 Отсортированная выборка: 12 14 22 36 51 55 58 63 82 89 Факт Наибольшая сумма: 420 Лучших перестановок: 1152 Расчёт Наибольшая сумма: 420 Лучших перестановок, не менее: 1152 Runtime = 00:00:02.46 Исходная выборка: 96 95 67 49 65 69 53 78 35 55 94 Отсортированная выборка: 35 49 53 55 65 67 69 78 94 95 96 Факт Наибольшая сумма: 348 Лучших перестановок: 11520 Расчёт Наибольшая сумма: 348 Лучших перестановок, не менее: 5760 Runtime = 00:00:29.21 Исходная выборка: 50 43 39 64 59 18 81 16 44 12 15 77 Отсортированная выборка: 12 15 16 18 39 43 44 50 59 64 77 81 Факт Наибольшая сумма: 463 Лучших перестановок: 28800 Расчёт Наибольшая сумма: 463 Лучших перестановок, не менее: 28800 Runtime = 00:06:26.81 АНАЛИЗ РЕЗУЛЬТАТОВ Во всех рассмотренных случаях тестирование полностью подтвердило предлагаемое общее решение.

    Ответ 3



    Предлагаю следующий алгоритм: Сортируем входной массив Поочередно берем элементы с конца его первой половины и с конца его второй половины Если длина массива нечетная, берем самый центральный элемент и помещаем его в начало или в конец, в зависимости от того, где больше разница с ним - слева или справа Код на C#: static void Main(string[] args) { //var input = new[] { 1, 2, 3, 4, 5 }; //var input = new[] { 1, 2, 3, 100, 200 }; //var input = new[] { 1, 2, 100, 200, 300 }; //var input = new[] { 22, 26, 48, 37, 47, 13, 9, 19 }; var input = new[] { 40, 27, 4, 9, 32, 35, 41, 39, 2 }; var combine = GetCombine(input); var sum = GetSum(combine); Console.WriteLine(string.Join(" ", combine)); Console.WriteLine(sum); } static int[] GetCombine(int[] input) { var len = input.Length; var sorted = input.OrderBy(x => x).ToArray(); var output = new int[len]; var d = 0; if (len % 2 == 1) { if (sorted[len / 2] - sorted[len / 2 - 1] > sorted[len / 2 + 1] - sorted[len / 2]) d = 1; output[(len - 1 + d) % len] = sorted[len / 2]; } for (int i = 0; i < len / 2; ++i) { output[2 * i + d] = sorted[len / 2 - 1 - i]; output[2 * i + 1 + d] = sorted[len - 1 - i]; } return output; } static int GetSum(int[] combine) { int sum = 0; for (int i = 0; i < combine.Length - 1; ++i) sum += Math.Abs(combine[i] - combine[i + 1]); return sum; } Проверить

    Python. Чем на самом деле является print?

    #python #python_2x #print #expressions

    
    Почему функция/оператор/набор символов (или что оно на самом деле) print не может
    работать в выражениях?
    
    Python 2.7.9 (default, Jun 29 2016, 13:08:31) 
    [GCC 4.9.2] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> print('hahaha')
    hahaha
    >>> 0 or print('hahaha')
      File "", line 1
        0 or print('hahaha')
                 ^
    SyntaxError: invalid syntax
    >>> def test(): print('hahaha')
    ... 
    >>> 0 or test()
    hahaha
    >>> 
    
        
    


    Ответы

    Ответ 1



    В Python 2.X print является ключевым словом (вроде return во многих языках), по этому после него выражение не обязательно должно быть заключено в скобки. И оно не является функцией и не может возвращать значения (даже None). По этому оно не может быть частью логического выражения: 0 or return("hahaha") В Pyton 3.X это фнукция. По этому там требуется ее аргументы заключать в скобки, и она возвращает None (который в логическом контексте действует как False), по этому такое логическое выражение не вызовет ошибок.

    Xml сериализация объектов со свойствами только для чтения

    #c_sharp #xml #сериализация

    
    
    
    При сериализации массива из объектов этого класса все атрибуты игнорируются, если
    у них нет setter'а. Вопрос: как решить проблему с этим явлением; класс не предусмотрен
    для изменения данных.
    
    /// 
    /// Представляет поля и методы для работы с абстракцией осциллятора.
    /// 
    [Serializable]
    public class Oscillator : IMixer
    {
        private Boolean enable;
        /// 
        /// Состояние вкл / выкл.
        /// 
        [XmlAttribute]
        public Boolean Enable
        {
            get
            {
                return enable;
            }
            set
            {
                enable = value;
            }
        }
    
    
        private Int32 volume;
        /// 
        /// Процентная громкость.
        /// 
        [XmlAttribute]
        public Int32 Volume
        {
            get
            {
                return volume;
            }
        }
    
    
    
        public Oscillator()
        {
    
        }
    
    
        public Oscillator(Boolean enable, Int32 volume)
        {
            this.enable = enable;
            this.volume = volume;
        }
    }
    
    
        //Вот, сама сериализация, если интересно.
        /// 
        /// Сохраняет пресет в Xml-файл.
        /// 
        /// 
        /// Путь к файлу.
        /// 
        /// 
        /// Массив осцилляторов для записи его в пресет.
        /// 
        public void SavePreset(String fileName, Oscillator[] oscs)
        {
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(Oscillator[]));
                using (Stream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
                {
                    serializer.Serialize(stream, oscs);
                    //for (Int32 i = 0; i < oscs.Length; i++)
                    //{
                    //    serializer.Serialize(stream, oscs[i]);
                    //}
                }
            }
            catch
            {
                throw new PresetException(PresetException.SaveError);
            }
        }
    
        
    


    Ответы

    Ответ 1



    Никак, это ограничение XmlSerializer. Only public properties and fields can be serialized. Properties must have public accessors (get and set methods). If you must serialize non-public data, use the DataContractSerializer class rather than XML serialization. В оригинальном ответе, как и в документации, советуют воспользоваться более гибким DataContractSerializer. Вариант с вырожденным сеттером, думаю, рассматривать не будем.

    Ответ 2



    Никак. Но вам это и не нужно. Вы должны иметь отдельные классы для сериализации/десериализации (и вообще любой транспортировки данных - DTO) и для бизнес-логики (POCO). И я рекомендую вам реализовать такое разделение как можно раньше, это позволит избежать глобальных ломающих изменений по мере развития проекта. Ссылка по теме: Наглядный пример различия DTO, POCO (POJO) и Value Object

    Что конкретно делает метод Thread.SpinWait?

    #c_sharp #net

    
    Из документации откровенно говоря ничего непонятно, все очень сумбурно. Что именно
    делает этот метод?
        
    


    Ответы

    Ответ 1



    Русский машинный перевод не очень хорош, лучше смотреть в свежий английский оригинал: SpinWait essentially puts the processor into a very tight loop, with the loop count specified by the iterations parameter. The duration of the wait therefore depends on the speed of the processor. то есть SpinWait на самом деле просто выполняет холостой цикл, количество итераций которого равно параметру iterations. Продолжительность ожидания, таким образом, зависит от скорости процессора. Для чего такое может понадобиться? Например, для оптимизации блокировки: если заблокированный ресурс скорее всего будет через несколько тактов процессора освобождён, то имеет смысл перед уходом на ожидание в режим ядра (что является медленной операцией) прокрутить несколько холостых циклов в надежде, что ресурс за это время освободится. Именно это делает lock/Monitor.Enter.

    Почему не работает подключение SVG файла c помощью img?

    #html #css #css3 #svg #анимация

    
    
    
    
      
      
      E
      Expire
    
    
    
    
    
    Сделал такой логотип с помощью SVG
    
    Сохранил в формате .svg, а потом попытался добавить на страницу с помощью тега img
    таким образом:
    
    asd
    
    
    По какой-то причине логотип не хочет добавляться, путь 100% правильный, имя файла
    тоже 100% правильное.
     Если же добавлять тот же самый код на страницу без сохранения в SVG файл, то все
    работает.
        
    


    Ответы

    Ответ 1



    Всё дело в том, что вы попали в ловушку разницы работы парсеров Html и xml Первый не выдает сообщение об ошибке отсутствия указания Namespaces. А файл svg не будет работать без указания Namespaces Для проверки попробуйте сохранить код вашего лого в файл с расширением *.svg. Код не будет выполнен и парсер xml выдаст сообщение об ошибке. Поэтому всегда добавляйте в шапке svg Namespaces Теперь вызов svg файла будет работать: image description Указывая ширину и высоту можно дополнительно регулировать размер лого. Следующий ваш вопрос будет почему не работает анимация при наведении. Потому что вы вызываете svg файл через Более подробно о других способах подключения файлов svg здесь

    Как сделать статическое свойство класса в питоне?

    #python #ооп

    
    Пробую так:
    
    class ChatCodes:
    
       _chat = 'cht'
    
       @property
       def chat(self):
          return self._chat
    
    
    если использую так:
    
    print(ChatCodes.chat + 'any_str')
    
    
    то появляется ошибка:
    
    
      unsupported operand type(s) for +: 'property' and 'str'
    
    
    как правильно создать статическое свойство?
        
    


    Ответы

    Ответ 1



    В принципе, объявленный параметр класса со значением - уже может использоваться как статическое свойство >>> class MyClass: ... param = "value" ... >>> MyClass.param 'value' >>> Это же значение будет доступно и для экземпляра класса. Разве что у экземпляра есть опасность, что значение свойства изменится в процессе работы. Тут стоит позаботиться, чтоб этот параметр не изменялся и/или чтоб обращение к свойству шло исключительно через имя класса, а не экземпляра. Можно использовать статический метод - объявляется с помощью аннотации @staticmethod. Правда и обращаться к нему придётся как к методу, а не свойству >>> class MyClass: ... @staticmethod ... def param(): ... return "value" ... >>> MyClass.param >>> MyClass.param() 'value' >>> Если достаточно ленивой инициализации (то есть обращаться к свойству будем через экземпляр класса), то можно использовать аннотацию @property >>> class MyClass: ... @property ... def param(self): ... return "value" ... >>> MyClass.param >>> MyClass.param() Traceback (most recent call last): File "", line 1, in TypeError: 'property' object is not callable >>> >>> m = MyClass() >>> m.param 'value' Ну и вариант на любителя (на случай, когда значение свойства нужно вычислить): >>> class MyClass: ... def _method_to_create_static_prop(): ... return "value" ... param = _method_to_create_static_prop() ... del _method_to_create_static_prop ... >>> MyClass.param 'value' >>> MyClass._method_to_create_static_prop Traceback (most recent call last): File "", line 1, in AttributeError: class MyClass has no attribute '_method_to_create_static_prop' >>>

    Ответ 2



    Если вы хотите, чтобы C.class_property вызывало бы метод класса, можно метакласс __getattr__ метод определить: #!/usr/bin/env python3 import random class ClassPropertyMeta(type): def __getattr__(cls, key): if key == 'class_property': return cls._get_class_property() raise AttributeError(f"<{cls!r}.{key!r}>") class C(metaclass=ClassPropertyMeta): @classmethod def _get_class_property(cls): return random.random() print(C.class_property) # -> 0.333495437410268 Аналогично для модулей в Питоне 3.7 (PEP 562): #!/usr/bin/env python3 import random def __getattr__(name): print(name) return random.random() if __name__ == '__main__': import module_attr print(module_attr.module_property) # -> module_property # -> 0.420563286888762

    Влияет ли размер css файла на загрузку страницы?

    #html #css #вёрстка

    
    К примеру у меня в css файле написано более 1к строк или к примеру файл весит более
    1 мб... Может ли это повлиять на загрузку страницы?
    
    Если к примеру для каждой страницы(к примеру) писать отдельный css файл, получается
    страница будет быстрее загружаться?
        
    


    Ответы

    Ответ 1



    Вес всего, что вы размещаете на странице будет влиять на её загрузку. Однако, есть и вторая сторона вопроса. Разбив файл на множество мелких, подгружая их в каждом нужном разделе, вы увеличиваете количество запросов, необходимых для чтения этих файлов. Что же делать, в такой ситуации? 1) Используйте сжатие. Пример, тут. 2) Уменьшайте количество стилей путем переноса в нужные страницы, но, только там, где страницы не индексируются или находится единичный элемент. Пример: Код формы или страницы регистрации можно вынести в отдельный файл. В общем-то, для всех служебных участков, которые закрыты от индексации можно писать отдельные стили. Если основной слайдер на главной странице более нигде не размещается, тогда вынесите его стили в inline. Если говорить обобщенно, в основной таблице оставляйте только те стили, которые участвуют на всех видимых страницах по несколько раз. 3) Некоторым стилям задавайте отдельные классы и используйте их при работе с HTML. Например: Запишите transition: all .5s; таким образом: .transition { -webkit-transition: all .5s; -o-transition: all .5s; transition: all .5s; } Затем подставляйте этот класс непосредственно при работе с кодом страницы.
    ...
    Таким образом вы существенно уменьшите количество повторов для таких стилей как user-select, элементов Flexbox и других. Все эти советы применимы и к файлам JS. Обобщенно говоря, ваша задача максимально уменьшить размер всего, что загружается на странице, не только файлов, но и их количества. Если кто-то что-то добавит, будет вообще супер!

    Ответ 2



    Конечно влияет. Но только при первом обращении, далее любой нормальный браузер просто закеширует его. Если хотите чтобы уж очень быстро, используйте inline стили, но это сами понимаете не очень красиво и тем более не очень удобно и практично. Хотя я использовал такой подход при работе с Vue.js например для разработки админ панели. Если для вас важно СЕО, думаю это не очень хорошая идея. Насчет разбить на страницы, можно с точки зрения удобства разработки, но не забывайте что это повлечет за собой и увелечение кол-ва запросов к серверу. Хотя если вы используете какой нибудь Webpack то это не проблема насколько я знаю.

    Ответ 3



    Может ли это повлиять на загрузку страницы? Логически да, практически (и да и нет). Сжатие. Если у вас в css комментарии, пробелы, переносы строк, то первое о чем вам стоит задуматься, это об оптимизации css, а точнее о его сжатии, максимальном. Т.е. когда вы откроете файл, там все будет в 1 строку, без лишних пробелов и т.д и т.п. Кэширование статических файлов. Как мы знаем, браузеры умеют хранить кэш веб-страниц. Вот тут то там и поможет как минимум ускорить загрузку страниц, так это кэширование файлов которые часто используются, но не часто изменяются, или совсем никогда.