Страницы

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

суббота, 27 октября 2018 г.

Переключение между вкладками Chrome, зная tabId этих вкладок

Здравствуйте.
Хочу реализовать переключение между вкладками Google Chrome в своём расширении. Расширение уже узнаёт id вкладок и может их обновлять.
Возможно ли сделать переключение между необходимыми мне вкладками, зная их tabId?


Ответ

Для этого используйте updateProperties в методе .update()
chrome.tabs.update(tabId, { active: true });

Способ расширения/наследование/декорирования 2D массива

Существует ли какой-либо способ расширить встроенный прямоугольный массив в c#? Например:
public class Array2D:???? { private T[,] _data;
public Array2D(T[,] vals) { _data = vals; }
public IEnumerable Row( int iRow) { return _data.Cast().Select((t, j) => _data[iRow, j]); } }


Ответ

Использовать методы расширения?
public static class TwoDimensionalArrayExtensions { public static IEnumerable Row(this T[,] array, int iRow) { if (array == null) { throw new ArgumentNullException(nameof(array)); } if (iRow < array.GetLowerBound(0) && iRow > array.GetUpperBound(0)) { throw new ArgumentOutOfRangeException(nameof(iRow)); }
for (int columnIndex = array.GetLowerBound(1); columnIndex <= array.GetUpperBound(1); columnIndex++) { yield return array[iRow, columnIndex]; } } }
Использование:
static void Main(string[] args) { var array = new int[2, 2] { { 1, 2 }, { 3, 4 } }; foreach (var value in array.Row(0)) { Console.WriteLine(value); } }

Задача про паркет

Есть поле из клеток, размеры которого [n * m]. Необходимо покрыть это поле плитками размера [1 * 2] (их можно поворачивать) таким образом, чтоб все клетки поля были накрыты, и чтоб плитки не вылазили за границы поля. Задача состоит в том, чтоб найти количество таких покрытий.
Данную задачу я решил с помощью динамики по профилю. Профиль - состояние одного столбца поля. Подразумевается, что слева от данного профиля уже все клетки заполнены, а справа ещё нет. Переход из профиля в профиль существует, если можно корректно положить некоторое количество плиток (переходы хранятся в матрице dp).
Затем я считаю матрицу ответов:
if (dp[j][i]) ans[k][i] += ans[k - 1][j];
И после посчитанной матрицы ответов считаю ответ на задачу
if (isFinishing(i)) res += ans[m - 1][i];
Эта строчка означает, что если профиль может являться завершающим, то добавить это число в ответу.
Данное решение вполне себе работает. Но затем я нашел модификацию данной задачи. Модификация состоит в том, чтобы найти количество таких покрытий, в которых не будет сплошных линий из плиток [1 * 2].
Пример:
Первая картинка - это пример того, какими должны быть покрытия, вторая - какими не должны.
У меня был вариант хранить в динамике ещё состояние для каждой строки, была ли она перекрыта хоть раз вертикальной плиткой, и добавлять к ответу только эти варианты. Возможно, это бы и работало, но я не особо понимаю, как это реализовать.
Подскажите, как реализовать, или предложите свои варианты решения.


Ответ

Можно сделать динамически по рядам длины n. Для каждого промежуточного решения хранить состояние "дырок", куда можно подставить вертикальные плитки. Установим, что мы всегда движемся сверху вниз, значит дырки будут внизу. Динамический массив будет иметь вид:
[int ряды, bool[] дырки] = кол-во решений
Например, все возможные решения для 1 ряда длиной 4:
[1, [0, 0, 1, 1]] = 1 // [xx] . . [1, [1, 0, 0, 1]] = 1 // . [xx] . [1, [1, 1, 0, 0]] = 1 // . . [xx] [1, [1, 1, 1, 1]] = 1 // . . . .
0 - горизонтальная плитка, 1 - пустое место для будущей вертикальной плитки. Количество нулей идущих подряд всегда должно быть парным, все нули запрещены (что бы удовлетворить ваше условие).
Дальше мы пытаемся соединить решение для x-1 рядов с решением для 1 ряда, что бы получить решение для x рядов:
for (prev in solutions[x-1]) for (single in solutions[1]) { if (дырки prev совместимы c дырками single) { holes = считаем как будут выглядеть дырки после совмещения 2 решений solutions[x][holes] += prev; } }
Конечным решением будет значение solutions[m, [0, 0, 0, 0, ... 0]], где все нули - это полностью заполненный последний ряд.
Возможно существует более элегантное решение.

Java 8 stream map to new Objects

Как можно замапить стрим в новые объекты? Или, эти примеры что не равнозначны?
list.stream().map(new SomeObject()::convertToSomeObject)
list.stream().map(item -> new SomeObject().convertToSomeObject(item))
public SomeObject convertToSomeObject(Item item) { this.name = item.getName; this.value = item.getValue; return this; }
в первом случае у меня все замапилось одним объектом


Ответ

Почему не работает первый вариант
При выполнении строчки
list.stream().map(new SomeObject()::convertToSomeObject)
происходит следующее:
до вызова метода map создаётся новый объект SomeObject ссылка на метод этого объекта передаётся в качестве параметра-лямбды в метод map берутся по очереди все элементы старого потока, к ним применяется переданный метод из полученных в результате применения метода новых объектов создаётся новый поток
Здесь объект SomeObject создаётся ровно один раз, и так как его метод convertToSomeObject всегда возвращает единственный созданный экземпляр, то и получается, что новый поток состоит из ссылок на один и тот же объект. При этом метод convertToSomeObject вызывался для каждого элемента потока и каждый раз значения полей объекта перезаписывались
Почему работает второй варинат
При выполнении строчки
list.stream().map(item -> new SomeObject().convertToSomeObject(item))
происходит следующее:
никаких объектов SomeObject до вызова map не создаётся в метод map передаётся лямбда-функция, которая работает как обычная функция:
принимает объект item создаёт новый экземпляр класса SomeObject вызывает метод convertToSomeObject у созданного экземпляра возвращает результат вызова метода convertToSomeObject, то есть только что созданный экземпляр класса SomeObject заметим, что лямбда-функция создаёт новый объект при каждом вызове
Как исправить первый вариант
написать конструктор SomeObject, принимающий Item в качестве параметра:
public SomeObject(Item item) { this.name = item.getName(); }
list.stream().map(SomeObject::new) добавить в класс SomeObject статический метод, принимающий Item и возвращающий SomeObject
public static SomeObject convertToSomeObject(Item item) { SomeObject object = new SomeObject(); object.name = item.getName(); return object; }
list.stream().map(SomeObject::convertToSomeObject) Перенести метод convertToSomeObject в класс Item
public SomeObject convertToSomeObject() { SomeObject object = new SomeObject(); object.name = this.getName(); return object; }
list.stream().map(Item::convertToSomeObject)

Как создать гибкую схему таблиц для хранения сообщений из разных чатов?

Помогите пожалуйста разобраться в следующей ситуации:
Есть два вида API где хранятся истории сообщений, это Zopim и Chat2Desc(импортировать в Postman) . Пока эти два но могут потом и другие появится.
И моя ДБ с таблицей users
Table users id , email, phone, ...
В Zopim пользователи идентифицируются через email, a в Chat2Desc через телефон. Для меня эти два поля важны, какой бы чат не был и сколько бы их не было.
То есть если я получаю емайл либо телефон пользователя в сообщениях, то делаю запрос в свою базу (table users) для идентифицирования своего пользователя.
Да и в принципе даже структура чатов не важна, я данные как нибудь да выберу.А вот как их правильно сохранить , да так чтоб у меня была одна структура для всех .
И вот что я придумал:
Разъяснение:
Таблица chats (Данные для чата) :
client_id - указывает на id таблицы chat_clients duration - длительность чата system_type - хранит имя чата (Zopim, Chat2Desc, ... ) created_at - дата создания
Таблица chat_clients (сведений об пользователей которые были в чате):
assigned_data - те инициалы под которыми пользователи были в чате is_agent - (0 | 1): 1 => мой пользователь, 0 => не мой users_id - id пользователя. Содержит либо id из таблицы users либо пустой. bean_module - неважно (сведение о моём пользователе) unique_col - Тут будет либо email (из Zopim) либо телефон (из Chat2Desc, Либо думаю хранить id таблицы users).Будет гарантировать уникальность значений.
Связка users_id + unique_col уникальна (UNIQUE KEY user_id_unique_col_UQ (user_id,unique_col))
Таблица chat_messages
text - текст сообщения. client_id - указывает на id таблицы chat_clients chat_id - указывает на id таблицы chats file_id - указывает на id таблицы chat_files transport - значение будет для Chat2Desc (Viber, WhatsApp ,...), для Zopim ,чтоб не пустовал , Zopim
Таблица chat_files Сведения о переданных файлах в чате.Aналогичных таблиц может быть может нет для хранения дополнительной инфы.
Доп инфо: В дальнейшем собираюсь для каждого пользователя выводит историю сообщений.
Вопрос: Как создать гибкую схему таблиц для хранения сообщений из разных чатов ?
Заранее благодарю.


Ответ

Любые проблемы по созданию БД нужно разбивать на две части:
Нужно выделить то, что уже есть. Выделить данность, реальность. То, что вы не можете изменить. То есть, выделить структуру внешних данных. Нужно выделить то, что вы хотите получить. Желаемый вид и форма.
У вас в структуре всё в одной куче. И материальное представление, и логический вид. Вам нужно выделить отдельные структуры под хранения данных из каждой отдельной системы чатов, которые вы поддерживаете. Так как структуры от­личаются ключами привязки к пользователям, это должны быть разные структуры. Нет, ко­не­чно, можно всё сделать в одной таблице, но тут вы ничего не приобретёте, но очень про­иг­ра­ете в сложности структуры. Если вам нужно делать уникальный ключ по двум ко­лонкам, то вы что-то делаете не так.
Затем нужно выделить то, что вы хотите получить. Значить вам нужна какая-то таблица свя­зки чатов и пользователей, и таблицы связки чатов в основной таблице и чатов в мате­риаль­ных таблицах. Если нужно хранить сообщения в каждом чате для быстрого доступа, то лучше будет это сделать явно, в отдельной таблице, не связанной с материальным пред­став­лением. Так сообщения будут храниться два раза, но вы не будете связаны материальным пред­став­лением после импорта сообщений, и ваш код получения данных из БД будет много проще и надёжней.
В современном мире нет смысла пытаться оптимизировать число таблиц в БД: если у вас их будет десять или сотня, само по себе это нисколько не повлияет на скорость работы с БД. Другое дело что сложная для понимания структура БД будет отнимать ваше время и на первоначальную разработку, и на дальнейшую поддержку. Если траты вашего времени можно избежать, то это следует сделать.
Сама сложная структура БД может представлять и сложность при масштабировании. Например, шардинг и уникальные индексы идут по разные стороны улицы: вы не можете использовать шардинг одновременно с уникальными индексами. То же можно сказать про скорость вставки записей: уникальные индексы ей не помогают.

функция давления кирпича пирамиды

Есть двумерная пирамида из кирпичей. Вес 1го - 1 кг, давит равномерно на 2 под ним по 0.5кг. То есть, если на верхний давит +100 кг, тогда под ним на каждый будет (100+1)/2 кг - на нижний давит пол веса каждого над ним.
1,0=.5 2,0=.75 2,1=1.5 3,0=.875 3,1=.2.125
Как вычислять давление на любой из них, указывая позицию, например, к4-2, к8-4 ... к(рядСверху,номерСлева) - как функция с 2 параметрами, возвращающая вес?
Думал, pяд*.5 + (pяд-1)/2 или 1*(c+1) / 2*p + 1*c / 2*p, разные другие варианты, но никак не могу подобрать точный. (желательно на java)


Ответ

А почему не воспользоваться рекурсией? Значения веса, номер ряда и номер кирпича в ряду вставляйте какие вам надо:
public static void main(String[] args) { float weight = 1; //вес кирпча int row = 5; //номер ряда начиная с 1 с верху int num = 3; //номер кирпича слева (или с права, как больше нравится) с 1 System.out.println(pressueOnBrick(row, num, weight)); }
//давление на один кирпич public static float pressueOnBrick(int row, int num, float weight) { return pressue(row, num, weight) - weight; //давление оказываемое на один кирпич = полное //давление которое оказывает кирпич минус вес кирпича }
//полное давление оказываемое кирпичём (включая свой вес) public static float pressue(int row, int num, float weight) { //в ряду не может быть кирпичей с номером меньше 1 и больше чем номер ряда(число кирпичей в ряду = номеру ряда) if (num < 1 || num > row) { return 0; }
//давление которое оказывает кирпич равно сумме веса кирпича и половине веса кирпичей которые давят на него //слева и справа return weight + (pressue(row - 1, num - 1, weight) + pressue(row - 1, num, weight)) / 2; }
Валидация вводимых значений на вашей совести.

Не получается из консольного .Net Core сослаться на библиотеку .Net Standard

Создал библиотеку .net-standard, в ней определил класс Class1 и константу MyConst
Далее создал консольное приложение .net-core, в нём набросал такой код:
class Program { static void Main(string[] args) { Console.WriteLine(Class1.MyConst); Console.ReadLine(); } }
В моем случае .Net Standard имеет версию 1.3, а .Net Core имеет версию 1.0.
UPD: Версия студии: Microsoft VS Enterprise 2017 v. 15.4.0
(!) Проблема в том, что не получается запустить консольное приложение. Консоль мигает примерно на миллисекунду, но не ведет себя как ожидается, то есть, не выводит константу с содержанием "Hello world" и не останавливается на Console.ReadLine();
В output выводится следующая инфо:
Программа "[8376] dotnet.exe" завершилась с кодом -2147450749 (0x80008083). Программа "[8376] dotnet.exe: Трассировка программы" завершилась с кодом 0 (0x0).
Ну да и из картинки видно, что к библиотеке .net-standard (в которой класс Class1, в котором константа MyConst) так же идет обращение из WPF-ного приложения (.Net Framework 4.6). Здесь добавил нугет пакет и ссылка на библиотеку работает нормально, то есть, приложение запускается и константа отображается. Думаю, что этот аспект к теме не относится.
Благодарю!


Ответ

По коду ошибки удалось найти:
Перечисление StatusCode, в котором указано поле с данным значением - CoreHostLibMissingFailure Место где используется поле CoreHostLibMissingFailure - read_config_and_execute
Можно сделать вывод, что отсутствуют требуемые версии библиотек. После установки .NET Core SDK 1.1.10 ошибка у меня воспроизводиться перестала.