• Как разбить многомерный массив на несколько по ключам?

    0xD34F
    @0xD34F
    $grouped = [];
    
    foreach ($arr as [ 'id' => $id, 'name' => $name, 'key' => $key ]) {
      $grouped[$key][$name] ??= [ 'name' => $name, 'ids' => [] ];
      $grouped[$key][$name]['ids'][] = $id;
    }
    
    foreach ($keys as $k) {
      $$k = array_map(fn($n) => [
        'name' => $n['name'],
        'ids' => implode(', ', $n['ids'])
      ], array_values($grouped[$k] ?? []));
    }
    Ответ написан
    1 комментарий
  • Как тестировать запросы и ответы из базы данных через phpunit?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Мне кажется, что найденные варианты работают не так. Используются они оба, а какой именно - зависит от того, что именно вы тестируете - запрос или ответ.

    Если говорить про "запросы к БД", то для таких тестов "массив с данными" использовать просто глупо. Это получится какой-то формальный тест: "проверяем, что метод возвращает массив из трех строк - и тут же возвращаем этот самый массив". В чем смысл? Если вы тестируете запрос к БД, то и надо тестировать запрос к БД. По-другому никак.

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

    И сюда же использование для тестов БД другой системы. Например основная БД MySQL, а для тестов используется Sqlite. Тут сразу можно сказать, что это профанация. Различие даже в какой-то одной настройке БД может повлиять на результаты запроса (и теста как следствие) - а тут и вовсе используется совсем другая БД.

    С другой стороны, работу с БД скорее стоит тестировать не в юнит тестах, а скажем в интеграционных. Но не будем углубляться.


    Массив же "с данными, симулирующими ответ из базы данных" используется на следующему уровне, там где требуется "ответ из базы данных". Взьмём метод, который использует данные, полученные из БД. Например авторизация юзера. Этот метод должен не сам лезть в базу, а дёргать отдельный метод, вполне возможно, что совсем другого класса. И вот чтобы протестировать авторизацию, вы и мокаете метод для работы с БД, и из этого мока возвращаете тот самый массив без всякого обращения к бд.

    Здесь нелишне будет напомнить название доклада с одной из последних конференций по пхп. Дословно не помню, но что-то вроде "Делайте методы как можно короче. Ваши тесты скажут вам спасибо." Собственно, именно при тестировании очень быстро начинаешь понимать удобство атомарных (то есть выполняющих какую-то одну простую операцию) методов. А без тестов пройдёт довольно много времени, пока не понадобится этот длинный метод отрефакторить, и по итогам менять кучу кода, который его вызывает.

    Так что разбивайте ваши длинные методы на мелкие, и тогда вопрос, как их тестировать, в большинстве случаев отпадёт сам собой.
    Ответ написан
    1 комментарий
  • Как сделать общий градиент для двух блоков?

    delphinpro
    @delphinpro Куратор тега CSS
    frontend developer
    Например так



    Для любого угла градиента

    Ответ написан
    5 комментариев
  • Почему код некорректно работает с кириллицей?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Неэффективность этого решения просто вопиёт к небу. Перебирать строку столько раз, сколько в ней букв - это же кощунство. Неужели нельзя за один проход посчитать символы, а за второй вывести их веса? И получить условные O(n*3) вместо O(n*3 + n^2).
    $len = mb_strlen($string);
    $counts = array_count_values(mb_str_split($string));
    foreach ($counts as $letter => $count) {
        echo "$letter: " . round($count / $len * 100, 1). "\n";
    }

    И заодно не придётся выковыривать из строки отдельные символы, которые мы уже выковыряли через mb_str_split.

    А для практики будет полезнее реализовать подсчет символов самостоятельно, без использования встроенной функции РНР
    Ответ написан
    Комментировать
  • Как в Apex Charts покрасить маркеры на графике в зависимости от значения?

    0xD34F
    @0xD34F Куратор тега JavaScript
    colors: markerColors, // Устанавливаем цвета маркеров в зависимости от результата

    Эта настройка предназначена для назначения цветов не отдельных маркеров, а относящихся к одному набору данных. Так что, чтобы заработало так, как вы хотите, придётся данные разделить. После чего использовать эту настройку станет уже необязательно - цвета можно задавать непосредственно внутри наборов данных. Недостаток - общей линией точки на графике не будут соединены.

    Другой вариант - воспользоваться свойством discrete, позволяющим индивидуально настраивать внешний вид каждого маркера. Всплывающую подсказку это никак не затрагивает, так что её придётся кастомизировать отдельно.
    Ответ написан
    Комментировать
  • Можно ли чтобы PHP Storm напоминал про GIT обновления?

    delphinpro
    @delphinpro Куратор тега PhpStorm
    frontend developer
    Если вы просто откроете настройки шторма и в поиске (слева вверху) просто напишите три буквы "git", то легко найдете настройку "Explicitly check for incoming commits remote", которую следует выставить в Always

    Так же можете изменить "Check for conflicts with the server every"
    Ответ написан
    Комментировать
  • Почему postgresql выбирает неоптимальный план выполнения для простого JOIN?

    Melkij
    @Melkij
    PostgreSQL DBA
    Я выполняю 2 одинаковых запроса

    "WHERE friends_info.user_id = 1" vs "WHERE friends_info.friend_id= 1"

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

    Bitmap Index Scan on ix_friends_user_id (cost=0.00..61.56 rows=5465 width=0) (actual time=0.742..0.743 rows=88 loops=1)

    Суть ошибки выбора плана. Какое распределение данных в таблице? Каков размер самой таблицы? Вероятно несколько пользователей занимают значительную часть таблицы и это сбивает оценку селективности.
    Простое чуть приподнять SET STATISTICS по полю, собрать новый analyze и посмотреть на оценку числа строк.

    PS: индекс ix_friends_user_id должен быть удалён как бесполезный при наличии friends_info_user_id_friend_id_key
    Ответ написан
    3 комментария
  • Как настроить возможность печати на разных локальных принтерах с общего RDP-сервера?

    @pfg21
    ex-турист
    объединить все компьютеры в единую локалку с помощью VPN
    куча проблем межкомпутерного взаимодействия сразу испарится.
    Ответ написан
    2 комментария
  • Как настроить возможность печати на разных локальных принтерах с общего RDP-сервера?

    hint000
    @hint000
    у админа три руки
    VPN-туннели между площадками и подклюние принтеров на сервере. Лучше, если принтеры сетевые и подключение будет сразу по ip-адресам принтеров. Хуже, если расшаривать доступ к принтерам на ПК, но всё равно худо-бедно будет работать.
    Вот всегда придёт поручик Ржевский и всё опошлит... (c)
    Да-да, VPN придуман в 90-х годах не для обхода блокировок, а именно для объединения удалённых офисов. Ну ещё для удалённого доступа сотрудников в командировках.
    Ответ написан
    Комментировать
  • Поиск на сайте. Как сделать "ничего не найдено"?

    0xD34F
    @0xD34F Куратор тега Vue.js
    const filteredProducts = computed(() => {
      const search = searchQuery.value.toLowerCase();
      return search.length > 2
        ? data.value.filter(n => n.title.toLowerCase().includes(search))
        : null;
    });

    <ul v-if="filteredProducts" class="search-result">
      <li v-if="!filteredProducts.length">
        <h3>ничего не найдено</h3>
      </li>
      <li v-for="n in filteredProducts">
        <div>
          <Image :src="n.image" :alt="n.title" width="40" height="40" />
        </div>
        <h3>{{ n.title }}</h3>
        <div>
          <p>{{ n.price }}</p>
        </div>
      </li>
    </ul>
    Ответ написан
    1 комментарий
  • Vue3 как показать скрыть элемент внутри v-for?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Показываем не более одного - добавляем в компонент свойство, которое будет содержать id, индекс или ещё что-то уникальное для каждого из элементов данных (да хоть бы и ссылку на сам элемент). Показываем скрытое в зависимости от равенства значения этого свойства тому, что доступно в текущей итерации v-for.

    Или, показываем несколько сразу - создаём отдельный компонент, в экземпляры которого будут передаваться элементы данных. Внутри компонента свойство, в зависимости от значения которого (истина-ложь) показываем или скрываем чего там надо.
    Ответ написан
    Комментировать
  • Как найти центральную ячейку таблицы?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Как получить строки таблицы:

    // если гарантируется отсутствие thead и tfoot, или их содержимое также должно учитываться
    const { rows } = table;
    
    // если tbody один
    const [ { rows } ] = table.tBodies;
    
    // если tbody несколько
    const rows = Array.prototype.flatMap.call(table.tBodies, n => [...n.rows]);
    // или
    const rows = [].concat(...Array.from(table.tBodies, n => [...n.children]));
    // или
    const rows = table.querySelectorAll('tbody tr');

    Как получить средний элемент:

    const middle = arr => arr[arr.length >> 1];
    // или
    const middle = arr => arr[Math.floor(arr.length / 2)];
    // или
    const middle = arr => arr[Math.round(~-arr.length / 2)];
    // или
    const middle = arr => arr[(arr.length - arr.length % 2) / 2];

    Всё, можно доставать ячейку:

    const cell = middle(middle(rows).cells);
    // или
    const cell = middle([].reduce.call(rows, (acc, n) => (acc.push(...n.children), acc), []));
    // или, без получения строк
    const cell = middle(table.querySelectorAll('tbody td'));
    Ответ написан
    Комментировать
  • Как зациклить эффект печати?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Строки сложить в массив. Завести два индекса - текущей строки и её последнего отображаемого символа. Если при увеличении количества отображаемых символов выходим за границу строки - переключаемся на следующую строку и сбрасываем счётчик символов.

    Куда, что и с какой задержкой будем печатать:

    const el = document.querySelector('p');
    const strings = [ 'hello, world!!', 'fuck the world', 'fuck everything' ];
    const delay = 100;

    Печатаем:

    function Typewriter(el, strings, delay) {
      let i = 0;
      let length = 0;
    
      return setInterval(() => {
        if (++length > strings[i].length) {
          i = -~i % strings.length;
          length = 0;
        }
    
        el.textContent = strings[i].slice(0, length);
      }, delay);
    }
    
    
    const intervalId = Typewriter(el, strings, delay);
    // хотим остановить, делаем так: clearInterval(intervalId);

    или

    function Typewriter(el, strings, delay) {
      let timeoutId = null;
    
      (function step(i, length) {
        length = -~length % -~strings[i].length;
        i = (i + !length) % strings.length;
        el.innerText = strings[i].substring(0, length);
        timeoutId = setTimeout(step, delay, i, length);
      })(0, 0);
    
      return () => clearTimeout(timeoutId);
    }
    
    
    const stop = Typewriter(el, strings, delay);
    // хотим остановить, делаем так: stop();
    Ответ написан
    1 комментарий
  • Почему в результате сложения получается Not-a-Number?

    Rsa97
    @Rsa97
    Для правильного вопроса надо знать половину ответа
    Вы берёте childNodes, куда входят не только элементы, но и текстовые узлы между элементами (переводы строк).
    // [object NodeList] (7)
    [#text,<div/>,#text,<div/>,#text,<div/>,#text]
    Так вот у этих текстовых узлов нет параметра offsetWidth, соответственно вы складываете undefined, получая NaN.
    - let box = document.querySelector(".box").childNodes;
    + let box = document.querySelector(".box").children;
    - box.forEach((item) => {
    + for (let item of box) {
    - })
    + }
    Ответ написан
    Комментировать
  • Как сделать JS/CSS слайдер с использованием flex элементов?

    delphinpro
    @delphinpro Куратор тега CSS
    frontend developer
    как-то так
    Ответ написан
    4 комментария
  • Как сгруппировать массив в одномерный с соединением ключей и значений?

    0xD34F
    @0xD34F
    function getCombinations($arr, $keys = [], $vals = []) {
      return ($n = $arr[count($keys)] ?? null)
        ? array_merge(...array_map(
            fn($k) => getCombinations(
              $arr,
              [ ...$keys, $k ],
              [ ...$vals, ...$n[$k] ]
            ),
            array_keys($n)
          ))
        : [ implode('_', $keys) => $vals ];
    }
    Ответ написан
    1 комментарий
  • Как реализовать идеальный метод indexOf?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Вы неверно понимаете суть О-нотации. Почитайте книги Дональда Кнута про это.
    O(3) - это то же самое, что O(1). Нет разницы. O(N), O(N+1000), O(10*N) - это тоже одно и то же.
    В таких случаях речь всегда идёт не про конкретный кейс, а про обобщенный. Вы не знаете в каком порядке элементы вашего массива, где находится искомый, сколько всего элементов будет в конкретных кейсах, поэтому определяется ряд случаев: средний (по вероятности, если входные данные рандомные), худший (чтобы понимать границы и сколько может "висеть" алгоритм теоретически). Лучшие варианты обычно никого не интересуют, потому что и вероятность их мала, и смысла никакого нет в столь малых величинах.

    У вас типичный случай компромисса в реализации структуры данных. Вы всегда балансируете между памятью и скоростью. Больших семь шапок из овцы не выкроить никак.
    То есть, вы можете сделать такую структуру данных, которая "под капотом" будет держать древовидный индекс с данными или отсортированную по ключу карту значений для бинарного поиска. Хотя эти варианты - суть одно и то же.
    Если не рассматривается вариант размена производительности на память, то в этой задаче у вас будет только O(N) без вариантов.
    Если усложнить структуру данных, то можно добиться и O(logN) при поиске, и даже O(1). Почитайте как устроен словарь в питоне.

    Да, помимо сложности поиска у вас будет сложность вставки в структуру новых элементов. И тут опять трейд-офф. Ну а что вы хотели?
    Ответ написан
    3 комментария
  • Как добавить/ удалить класс каждые 3 секунды в Vue?

    0xD34F
    @0xD34F Куратор тега Vue.js
    const blocks = ref(Array.from({ length: 5 }, (_, i) => (-~i) ** 2));
    const active = ref(0);
    
    function next() {
      active.value = (active.value + 1 + blocks.value.length) % blocks.value.length;
    }
    
    let intervalId = null;
    onMounted(() => intervalId = setInterval(next, 500));
    onUnmounted(() => clearInterval(intervalId));

    <div
      v-for="(n, i) in blocks"
      v-text="n"
      :class="[ 'box-item', { active: i === active } ]"
    ></div>

    Конечно, зашивать в стили цвета блоков и их количество - все эти :nth-child - не круто. Лучше сделать компонент, принимающий массив цветов и создающий блоки на его основе. Соответственно, вместо класса будет назначаться цвет фона напрямую, как-то так:

    <div
      v-for="(n, i) in colors"
      :style="{ backgroundColor: i === active ? n : '' }"
      ...
    Ответ написан
    2 комментария
  • Как сделать кнопку такой фигурой?

    Get-Web
    @Get-Web Куратор тега CSS
    Front-End Developer
    clip-path. Как раз есть пример с анимацией:
    Ответ написан
    Комментировать
  • Как максимально просто создать фигуру как на изображении для последующей анимации?

    sfi0zy
    @sfi0zy Куратор тега CSS
    Creative frontend developer
    Вариант с градиентами - сложный для анимирования. Рисование линий со stroke-dasharray - это стандартный выбор. Но dash array может быть длинным, им можно описать самые разные последовательности линий и пробелов, так что если вам не нужны разные цвета, то можно сделать одну линию:

    Ответ написан
    5 комментариев