Задать вопрос
Ответы пользователя по тегу JavaScript
  • Почему неправильно считается сумма двух минимальных элементов массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const newArray = numbers.filter(i => i !== firstMin);

    Что, если минимальный элемент представлен в нескольких экземплярах? Вы их все выкинете.

    Можно найти индекс минимального элемента и фильтровать по индексу:

    function sumTwoSmallestNumbers(nums) {  
      const iMin = nums.indexOf(Math.min(...nums));
      return nums[iMin] + Math.min(...nums.filter((_, i) => i !== iMin));
    }

    Это если идти вашим путём. Но есть и иные способы решить задачу. Например, можно отсортировать массив и взять два крайних элемента:

    const sumTwoSmallestNumbers = ([...nums]) => nums
      .sort((a, b) => b - a)
      .slice(-2)
      .reduce((acc, n) => acc + n, 0);

    Или, сосчитать, кто сколько раз повторяется и выбирать второе слагаемое в зависимости от количества повторений первого:

    function sumTwoSmallestNumbers(nums) {
      const count = Object.entries(nums.reduce((acc, n) => (acc[n] = -~acc[n], acc), {}));
      return +count[0][0] + +count[+(count[0][1] === 1)][0];
    }

    Или, пройти по массиву один раз, запоминая встреченные элементы, если они меньше тех, что вам уже попадались (т.е., сделать то, чего от вас тут и ожидается - решить задачу с линейной сложностью по времени и константной по памяти):

    function sumTwoSmallestNumbers(nums) {
      let min1 = Infinity;
      let min2 = Infinity;
    
      for (const n of nums) {
        if (n < min1) {
          [ min1, min2 ] = [ n, min1 ];
        } else if (n < min2) {
          min2 = n;
        }
      }
    
      return min1 + min2;
    }
    
    // или
    
    const sumTwoSmallestNumbers = nums =>
      eval(nums.reduce(([ min1, min2 ], n) => 
        n < min1 ? [    n, min1 ] :
        n < min2 ? [ min1,    n ] :
                   [ min1, min2 ]
      , [ Infinity, Infinity ]).join('+'));
    Ответ написан
  • Возможно ли обработать Promise.all без второго Promise.all?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Promise
      .all(urls.map(url => fetch(url).then(result => result.json())))
      .then(results => results.forEach(result => console.log(result.id)));
    Ответ написан
    Комментировать
  • Как перемножить два массива?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Как перемножить элементы массива:

    const mul = arr => arr.reduce((acc, n) => acc * n, 1);

    Бежим по массиву с количествами элементов, получаем из массива с данными подмассивы указанной длины, перемножаем их содержимое:

    const result = count.map(function(n) {
      return mul(data.slice(this[0], this[0] += n));
    }, [ 0 ]);

    Или, если массив с данными больше не понадобится, можно всегда вырезать у него из начала указанное количество элементов:

    const result = count.map(n => mul(data.splice(0, n)));
    Ответ написан
    1 комментарий
  • Слияние объектов не работает в "codewars", можете объяснить пожалуйста?

    0xD34F
    @0xD34F Куратор тега JavaScript
    function combine(a = {}, b = {}, c = {}) {

    Читаю текст задачи сверху вниз, снизу вверх, так, сяк, наперекосяк, и никак не могу найти там место, где говорится, что объектов в функцию будет передаваться не больше трёх.

    Как обработать заранее неизвестное количество аргументов?

    Можно собрать их в массив:

    const combine = (...arr) => arr
      .flatMap(Object.entries)
      .reduce((acc, [ k, v ]) => (acc[k] = (acc[k] ?? 0) + v, acc), {});

    Или, воспользоваться уже готовым массивоподобным объектом:

    function combine() {
      const result = {};
    
      for (const n of arguments) {
        for (const k in n) {
          if (n.hasOwnProperty(k)) {
            if (!result.hasOwnProperty(k)) {
              result[k] = 0;
            }
    
            result[k] += n[k];
          }
        }
      }
    
      return result;
    }
    Ответ написан
    1 комментарий
  • Как найти самое часто встречаемое число в массиве?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const mostFrequentNum = Array
      .from(arr.reduce((acc, n) => acc.set(n, -~acc.get(n)), new Map))
      .reduce((max, n) => max[1] > n[1] ? max : n, [ , 0 ])
      .at(0);

    или

    const mostFrequentNum = Object
      .entries(arr.reduce((acc, n) => (acc[n] = (acc[n] ?? 0) + 1, acc), {}))
      .reduce((acc, n) => (acc[n[1]] = +n[0], acc), [])
      .pop();
    Ответ написан
    2 комментария
  • Вложенной деструктуризации массива не существует?

    0xD34F
    @0xD34F Куратор тега JavaScript
    let [0: [fruit1, fruit2, fruit3]] = arr; //Uncaught SyntaxError: Invalid destructuring assignment target

    Скажите, а когда массив создаёте, вы тоже индексы явно прописываете? Ну вот и тут не надо.
    А если надо пропустить какие-то индексы - просто добавьте запятых:

    const arr = [
      [ 1, 2, 3 ],
      [ 5, 6, 7 ],
      [ 7, 8, 9 ],
    ];
    
    const [ , [ , val1 ], [ ,, val2 ] ] = arr;
    
    console.log(val1, val2); // 6 9

    Или можно заменить квадратные скобки фигурными - массив это тоже объект.
    Так что и деструктурировать его как обычный объект не возбраняется:

    const arr = [
      [ 1, 2, 3 ],
      [ 5, 6, 7 ],
      [ 7, 8, 9 ],
    ];
    
    const { 1: { 1: val1 }, 2: { 2: val2 } } = arr;
    
    console.log(val1, val2); // 6 9
    Ответ написан
    Комментировать
  • Как у объекта в sessionStorage получить проверку количества ключей?

    0xD34F
    @0xD34F Куратор тега JavaScript
    раз:

    The keys and the values are always in the UTF-16 string format...

    два
    Ответ написан
    Комментировать
  • Как отсортировать узлы дерева?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Object.values(t).forEach(n => {
      n.children?.sort((a, b) => (a.order - b.order) || a.name.localeCompare(b.name));
    });
    Ответ написан
    2 комментария
  • Как перемножить числа в том же массиве?

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

    const square = n => n ** 2;
    
    // или
    
    const square = n => n * n;
    
    // или
    
    const square = n => Math.pow(n, 2);

    Как обновить массив:

    arr.forEach((n, i, a) => a[i] = square(n));
    
    // или
    
    arr.splice(0, arr.length, ...arr.map(square));
    
    // или
    
    for (const [ i, n ] of arr.entries()) {
      arr[i] = square(n);
    }
    
    // или
    
    for (let i = 0; i < arr.length; i++) {
      arr[i] = square(arr[i]);
    }
    Ответ написан
    3 комментария
  • Почему выводится ошибка Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'push')?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Так написано же всё в сообщении об ошибке. Кинуть в консоль получаемые данные догадались, а произвести аналогичную операцию над table.data и увидеть, что оно undefined - уже нет?

    Как мне изменить код, чтобы исправить ошибку?

    Код настолько отвратительный, что я бы переписал с нуля:

    const countries = Array.from({ length: 3 }, prompt);
    
    new gridjs.Grid({
      columns: [
        'Code',
        { name: 'Flag', formatter: val => gridjs.html(`<img src="${val}">`) },
        'Name',
        'Capital',
        'Population',
      ],
      data: () => Promise.all(countries.map(n =>
        fetch(`//restcountries.com/v3.1/name/${n}`)
          .then(r => r.json())
          .then(([ r ]) => [
            r.altSpellings[0],
            r.flags.png,
            r.name.common,
            r.capital[0],
            r.population,
          ])
          .catch(() => [ ,,`${n} - это не страна`,, ])
      )),
    }).render(document.querySelector('#wrapper'));
    Ответ написан
  • Как выдернуть массив чисел из строки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    (str.match(/[0-9]+/g) ?? []).map(Number)
    
    // или
    
    Array.from(str.matchAll(/\d+/g), n => +n)
    
    // или
    
    str.split(/\D+/).filter(Boolean).map(parseFloat)
    
    // или
    
    eval(`[${str.replace(/\D+/g, (m, i) => i ? ',' : '')}]`)
    
    // или
    
    [...str].reduce((acc, n, i, a) => (
      isNaN(n) || (isNaN(a[i - 1]) && acc.push(0), acc.push(acc.pop() * 10 + n * 1)),
      acc
    ), [])
    Ответ написан
    Комментировать
  • Преобразование объекта в примитив, почему прилетает object Object?

    0xD34F
    @0xD34F Куратор тега JavaScript
    ищет метод toString - его нет

    То есть, если попробовать получить test.toString, то результатом будет undefined. Вы проверьте, так ли это. Будете удивлены.
    Ответ написан
  • Как получить значение ячейки th и присвоить это значение в data-attr td?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Какие таблицы будем обрабатывать:

    const tables = document.querySelectorAll('селектор таблиц');

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

    for (const { tHead, tBodies } of tables) {
      const labels = Array.prototype.map.call(
        tHead.rows[0].cells,
        th => th.textContent
      );
    
      for (const { rows } of tBodies) {
        for (const { cells } of rows) {
          for (const [ i, label ] of labels.entries()) {
            cells[i].dataset.label = label;
          }
        }
      }
    }

    или

    tables.forEach(table => {
      table.querySelectorAll('tbody td').forEach(function(td) {
        td.setAttribute('data-label', this[td.cellIndex]);
      }, Array.from(table.querySelectorAll('thead th'), th => th.innerText));
    });
    Ответ написан
    Комментировать
  • Как собрать массив из двух других массивов по совпадению id?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const result = data
      .flatMap(n => n.values)
      .filter(n => n.Ids.some(m => arr.includes(m)))
      .map(({ id, title }) => ({ id, title }));

    или

    const inArr = Set.prototype.has.bind(new Set(arr));
    const data.reduce((acc, { values }) => (
      values.forEach(({ Ids, ...n }) => Ids.some(inArr) && acc.push(n)),
      acc
    ), []);
    Ответ написан
    1 комментарий
  • Как из двух массивов получить те объекты, которые есть в одном и отсутствуют в другом?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Делаем просто, ровно то, что спрошено в вопросе:

    const result = allCass.filter(function(n) {
      return !this.has(n.id);
    }, new Set(defaultCass.map(n => n.id)));

    Делаем сложно, решаем задачу в более общем виде (источником данных могут быть не обязательно массивы; условие, по которому значения признаются равными, не будем зашивать непосредственно в код - будет параметром функции):

    function* diff(data1, data2, key = n => n) {
      const getKey = key instanceof Function ? key : n => n[key];
      const keys = new Set;
    
      for (const n of data2) {
        keys.add(getKey(n));
      }
    
      for (const n of data1) {
        if (!keys.has(getKey(n))) {
          yield n;
        }
      }
    }

    В вашем случае применять так:

    const result = [...diff(allCass, defaultCass, 'id')];

    А можно и так:

    Array.from(diff('abcdE', 'AcD', n => n.toLowerCase())) // ['b', 'E']

    Или так:

    for (const n of diff(Array(8).keys(), Array(5).keys())) {
      console.log(n); // 5 6 7
    }
    Ответ написан
    6 комментариев
  • Как сформировать новый массив объектов, сделав слияние по некоторому параметру?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Пытался сделать через reduce из библиотеки lodash

    Давайте так - или lodash, или reduce, но не оба сразу:

    const newArr = _.map(_.groupBy(arr, 'merch'), (v, k) => ({
      merch: +k,
      games: _.uniq(_.flatMap(v, 'games')),
    }));

    const newArr = Object
      .entries(arr.reduce((acc, n) => ((acc[n.merch] ??= []).push(...n.games), acc), {}))
      .map(n => ({ merch: +n[0], games: [...new Set(n[1])] }));
    Ответ написан
    Комментировать
  • Как сделать сортировку по двум параметрам?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Сортируем существующий массив:

    arr.sort((a, b) => a.surname.localeCompare(b.surname) || a.name.localeCompare(b.name));

    Собираем отсортированный новый:

    const sorted = (arr, keys) => arr
      .map(n => [ n ].concat(keys(n)))
      .sort((a, b) => {
        let diff = 0;
        a.find((n, i) => diff = i && ((n < b[i]) ? -1 : +(n > b[i])));
        return diff;
      })
      .map(n => n[0]);
    
    
    const sortedArr = sorted(arr, n => [ n.surname.toLowerCase(), n.name.toLowerCase() ]);
    Ответ написан
    Комментировать
  • Почему заполняется только один select?

    0xD34F
    @0xD34F Куратор тега JavaScript
    selects[0].appendChild(option)
    selects[1].appendChild(option)

    Как один элемент может одновременно находиться внутри двух других элементов? Очевидно же, что никак:

    Если данный дочерний элемент является ссылкой на существующий узел в документе, то функция appendChild() перемещает его из текущей позиции в новую позицию

    Это должны быть два разных option'а. Можете во втором случае добавлять копию:

    selects[1].appendChild(option.cloneNode(true));

    Но вообще, вариант так себе. Появится ещё один select - побежите копипастить строку с добавлением option'а? Надо сделать цикл по select'ам. Например, так:

    selects.forEach(function(n) {
      n.append(...this.map(m => new Option(m[1].label, m[0])));
    }, Object.entries(metrics.convertRules));

    Или, можно собирать html вместо создания отдельных элементов:

    const optionsHTML = Object
      .entries(metrics.convertRules)
      .map(n => `<option value="${n[0]}">${n[1].label}</option>`)
      .join('');
    
    selects.forEach(n => n.innerHTML = optionsHTML);
    Ответ написан
  • Как заполнить произведение для каждой ячейки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    62b0f00f35c0f358713719.png

    "Добавить"? Понятно, почему ничего не получается - формы добавляются динамически, так что обработчики событий вы пытаетесь назначать элементам, которых ещё нет. Применим делегирование - обработчик добавляем один раз, выше форм, проверяем целевой элемент, если это оказался интересующий нас input, то поднимаемся от него к элементу формы, ищем внутри неё все input'ы и элемент, в который надо записать результат вычислений.

    document.addEventListener('input', e => {
      if (e.target.classList.contains('form-control')) {
        const form = e.target.closest('селектор формы');
        form.querySelector('span').innerText = Array
          .from(form.querySelectorAll('input.form-control'))
          .reduce((acc, n) => acc * (+n.value || 0), 1);
      }
    });
    Ответ написан
    Комментировать