const createTreeFromNestedSets = arr => [...arr]
.sort((a, b) => a.left - b.left)
.reduce((acc, n) => {
while (acc.at(-1).at(-1).right < n.left) {
acc.pop();
}
if (acc.at(-1).at(-1).right > n.left) {
acc.push(acc.at(-1).at(-1).children);
}
acc.at(-1).push({ ...n, children: [] });
return acc;
}, [ [ { left: -Infinity, right: Infinity, children: [] } ] ])
[0][0].children;
const createTreeHTML = (arr, nodeTemplate) =>
Array.isArray(arr) && arr.length
? `<ul>${arr.map(n => `
<li>
${nodeTemplate(n)}
${createTreeHTML(n.children, nodeTemplate)}
</li>`).join('')}
</ul>`
: '';
containerElement.insertAdjacentHTML('beforeend', createTreeHTML(
createTreeFromNestedSets(data),
item => `<input data-id="${item.id}" type="checkbox">${item.name}`
));
function getDates(startStr, endStr) {
const startDate = new Date(startStr.split('.').reverse().join('-'));
const endDate = new Date(endStr.split('.').reverse().join('-'));
const dates = [];
for (; startDate <= endDate; startDate.setDate(startDate.getDate() + 1)) {
dates.push(startDate.toLocaleDateString('ru-RU', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
}));
}
return dates;
}
const inputs = [...document.querySelectorAll('.input')];
inputs.forEach(n => n.addEventListener('input', onInput));
function onInput({ target: t }) {
if (t.value.length === t.maxLength) {
t.nextElementSibling?.focus();
}
if (inputs.every(n => n.value.length === n.maxLength)) {
// здесь дёргаете свою функцию
}
}
const blockSelector = '.block';
const buttonSelector = `${blockSelector} .block__close`;
document.addEventListener('click', e => {
const block = e.target.closest(buttonSelector)?.closest(blockSelector);
block?.parentNode.removeChild(block);
});
document.querySelectorAll(buttonSelector).forEach(function(n) {
n.addEventListener('click', this);
}, e => e.currentTarget.closest(blockSelector).remove());
не затрагивая строчку sort
users.sort((a,b) => a- b);
valueOf() {
return this.age;
},
toString
на[Symbol.toPrimitive](hint) {
return hint === 'number'
? this.age
: `${this.name} is ${this.age} y.o.`;
},
const svgEl = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
const pathEl = document.createElement('path');
const group = (arr, ...keys) =>
arr.reduce(((key, acc, n) => (
(keys.reduce((obj, k) => obj[n[k]] ??= {}, acc)[n[key]] ??= []).push(n),
acc
)).bind(null, keys.pop()), {});
const grouped = group(arr, 'order', 'user_id', 'stream_id', 'currency_id');
function group(data, keys) {
const result = {};
for (const n of data) {
const objKeys = [].concat(keys(n));
const arrKey = objKeys.pop();
(objKeys.reduce((obj, k) => obj[k] ??= {}, result)[arrKey] ??= []).push(n);
}
return result;
}
// ваш случай
group(arr, n => [ n.order, n.user_id, n.stream_id, n.currency_id ])
// а вообще, группировать можно не только массивы; количество признаков группировки
// может отличаться для различных элементов; сами признаки и имена групп не обязаны совпадать
// с какими-либо свойствами элементов, а могут являться производными от них значениями
group('12+345-!aщСxE_VЖg', n => {
const low = n.toLowerCase();
return (
low !== n.toUpperCase() ? [ 'буквы', n === low ? 'строчные' : 'заглавные' ] :
Number.isInteger(+n) ? [ 'цифры', (n & 1) ? 'нечётные' : 'чётные' ] :
'другое'
);
})
const find = (obj, key, val) =>
obj instanceof Object
? obj[key] === val
? obj
: Object.values(obj).reduce((found, n) => found ?? find(n, key, val), null)
: null;
const obj = find(fractal, 'id', id);
function find(obj, key, val) {
for (const stack = [ obj ]; stack.length;) {
const n = stack.pop();
if (n instanceof Object) {
if (n[key] === val) {
return n;
}
stack.push(...Object.values(n));
}
}
return null;
}
function sum(data) {
let result = 0;
for (const stack = [ data ]; stack.length;) {
const n = stack.pop();
stack.push(...(n instanceof Object ? Object.values(n) : []));
result += typeof n === 'number' ? n : 0;
}
return result;
}
<label>
Город:
<select id="city"></select>
</label>
<label>
Линия:
<select id="line"></select>
</label>
<label>
Станция:
<select id="station"></select>
</label>
fetch('https://api.hh.ru/metro/').then(r => r.json()).then(subwayData => {
const city = document.querySelector('#city');
const line = document.querySelector('#line');
const station = document.querySelector('#station');
const getLines = () => subwayData[city.value].lines;
const update = (el, data) => {
el.replaceChildren(...data.map((n, i) => new Option(n.name, i)));
el.dispatchEvent(new Event('change'));
};
city.addEventListener('change', () => update(line, getLines()));
line.addEventListener('change', () => update(station, getLines()[line.value].stations));
update(city, subwayData);
});
выводит не совсем то что мне надо
array.length
надо крутить цикл до array.length - n + 1
.const bullshitChunks = (arr, chunkSize) =>
Array.from(
{ length: arr.length - chunkSize + 1 },
(n, i) => arr.slice(i, i + chunkSize)
);
console.log(bullshitChunks([ 1, 2, 3, 4, 5, 6, 7 ], 4));
console.log(bullshitChunks('abcdefg', 5));
const selectors = [ '.addservice', '.addprice' ];
const data = Array.from(
document.querySelectorAll('.addserviceBlock'),
n => selectors.map(m => n.querySelector(m).value)
);
const headers = document.querySelectorAll('section > h2');
const menu = document.querySelector('что здесь должно быть, понятия не имею, сами разберётесь');
menu.innerHTML = Array
.from(headers, n => `<a href="#${n.parentNode.id}">${n.innerHTML}</a>`)
.join('');
for (const { parentNode: p, textContent: t } of headers) {
menu.insertAdjacentHTML(
'beforeend',
'<a href="#' + p.getAttribute('id') + '">' + t + '</a>'
);
}
menu.append(...Array.prototype.map.call(headers, n => {
const a = document.createElement('a');
a.href = '#'.concat(n.parentNode.attributes.id.value);
a.innerText = n.innerText;
return a;
}));
const wrapper = document.createElement('div');
const start = block.querySelector('.start');
for (let el; !(el = start.nextElementSibling).matches('.end'); wrapper.appendChild(el)) ;
start.insertAdjacentElement('afterend', wrapper);
const wrapper = document.createElement('div');
const children = [...block.children];
const iStart = children.findIndex(n => n.classList.contains('start'));
const iEnd = children.findIndex(n => n.classList.contains('end'));
wrapper.append(...children.slice(iStart + 1, iEnd));
children[iStart].after(wrapper);
data.reduce((acc, { unique, id, count, name }) => (
((acc[unique] ??= { count })[id] ??= []).push(name),
acc
), {})
function chunked(str, numChunks) {
const chunkSize = Math.ceil(str.length / numChunks);
return Array.from(
{ length: numChunks },
(n, i) => str.slice(i * chunkSize, (i + 1) * chunkSize)
);
}
function chunked(str, numChunks) {
return str.match(RegExp(`.{1,${Math.ceil(str.length / numChunks)}}`, 'g'));
}
function chunked(str, numChunks) {
return str.split(RegExp(`(.{${Math.ceil(str.length / numChunks)}})`)).filter(Boolean);
}
неаккуратненько как-то:
chunked('test', 3) // [ "te", "st", "" ]
const chunked = (str, numChunks) =>
numChunks <= str.length
? Array.from(
{ length: numChunks },
function(n, i) {
return str.slice(i * this, i === numChunks - 1 ? str.length : (i + 1) * this);
},
str.length / numChunks | 0
)
: 'извини, столько непустых кусков нарезать нельзя';
function chunked(str, numChunks) {
const chunkSize = str.length / numChunks | 0;
const numLooseItems = str.length % numChunks;
return Array.from(
{ length: numChunks },
function(_, i) {
return str.slice(this(i), this(i + 1));
},
i => i * chunkSize + Math.min(i, numLooseItems)
);
}