У меня есть массив, состоящий из ключей и значений, где ключи представляют собой древовидный нумерованный список. Это входной массив:
inputArr = [
["1", "p"],
["1.1", "q"],
["1.2", "a"],
["1.2", "b"],
["1.2", "c"],
["1.2.1", "d"],
["1.2.2", "4"],
["1.2.2.1", "5"],
["1.3", "6"],
["1.4x", "7"],
["2", "8"],
["2.1", "9"],
["2.2", "10"],
["2.2.1x", "11"],
["2.2.2", "12"],
["3", "13"],
["4", "14"]
];
Ожидаемый результат:
outputArr = [
["1.1", "p,q"],
["1.2.1", "p,a,b,c,d"],
["1.2.2.1", "p,a,b,c,4,5"],
["1.3", "p,6"],
["1.4x", "7"], // not "p,7", because key has a tailing 'x'
["2.1", "8,9"],
["2.2.1x", "11"], //not "8,10,11", because key has a tailing 'x'
["2.2.2", "8,10,12"],
["3", "13"],
["4", "14"]
];
Позвольте мне объяснить первый вывод: ["1.1", "p,q"]
:
Это первый лист. Это путь: "1" -> "1.1". Значения в пути: "p", "q".
Позвольте мне объяснить второй вывод: ["1.2.1", "p,a,b,c,d"]
:
Это второй лист.
Здесь я рассматривал повторяющиеся ключи как расширение одного. ["1.2", "a"],["1.2", "b"],["1.2", "c"]
означает ["1.2", "abc"]
.
Итак, путь второго листа: «1» -> («1.2» + «1.2» + «1.2») -> «1.2.1».
Позвольте мне объяснить пятый вывод:["1.4x", "7"]
:
Обратите внимание: это не "p,7". Поскольку у ключа есть хвост «x», этот лист не должен принимать «p» в выходных данных.
Та же логика применима и для седьмого выхода.
Что я сделал до сих пор:
Вот мои попытки решить этот вопрос на данный момент.
Это фрагмент кода, который я использую прямо сейчас:
//////////////////////////////////////
function getTreeBranch(arr, c, p) {
var outputArr = [],
s = [],
curr,
next;
for (var i = 0; i < arr.length - 1; i++) {
curr = arr[i];
next = arr[i + 1];
currLevel = curr[c].split(".").length
nextLevel = next[c].split(".").length
if (currLevel == 1) {
s = []
s.push(curr[p]);
if (currLevel == nextLevel)
outputArr.push([curr[c], s.join(',')]);
} else if (currLevel < nextLevel) {
s.push(curr[p]);
} else if (currLevel == nextLevel) {
s.push(curr[p]);
outputArr.push([curr[c], s.join(',')]);
s.pop();
} else if (currLevel > nextLevel) {
outputArr.push([curr[c], s.join(',') + ',' +curr[p]]);
for (j = 0; j < (currLevel - nextLevel); j++) {
s.pop()
}
}
}
var lastItem = arr[arr.length - 1];
if ((lastItem[c].length) == 1) {
s = []
}
s.push(lastItem[p]);
outputArr.push([lastItem[c], s.join(',')]);
return outputArr
}
Но эта функция не может обрабатывать повторяющиеся ключи и завершающие 'x'.
Можете ли вы предложить какое-либо исправление или обновление, какой-либо альтернативный фрагмент кода, какой-либо алгоритм или намек на проблему? Любая помощь будет высоко ценится.
Предотвратить разделение суффикса values with
'x'`.
const
getPathes = ({ value = [], sub }) => sub
? Object
.entries(sub)
.flatMap(([k, v]) => getPathes(v).map(([p, s]) => [
k + (p && '.') + p,
[...value, ...s]
]))
: [['', value]],
input = [["1", "p"], ["1.1", "q"], ["1.2", "a"], ["1.2", "b"], ["1.2", "c"], ["1.2.1", "d"], ["1.2.2", "4"], ["1.2.2.1", "5"], ["1.3", "6"], ["1.4x", "7"], ["2", "8"], ["2.1", "9"], ["2.2", "10"], ["2.2.1x", "11"], ["2.2.2", "12"], ["3", "13"], ["4", "14"]],
tree = input.reduce((t, [path, value]) => {
const
keys = path.endsWith('x')
? [path]
: path.split('.'),
target = keys.reduce((o, k) => (o.sub ??= {})[k] ??= {}, t);
(target.value ??= []).push(value);
return t;
}, {}),
result = getPathes(tree);
result.forEach(([k, v]) => console.info(k, ...v));
console.info(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Отфильтруйте листья, проверив, что нет других записей, которые имеют их в качестве родителя, создав особый случай для записей с «x».
Затем, предполагая, что inputArr
находится в правильном порядке, найдите всех родителей и включите их (опять же, с особым случаем, когда есть «x»).
const inputArr = [["1","p"],["1.1","q"],["1.2","a"],["1.2","b"],["1.2","c"],["1.2.1","d"],["1.2.2","4"],["1.2.2.1","5"],["1.3","6"],["1.4x", "7"],["1.4x", "s"],["1.4x", "g"],["2","8"],["2.1","9"],["2.2","10"],["2.2.1x","11"],["2.2.2","12"],["3","13"],["4","14"]]
const outputArr = [...new Set(inputArr.map(([k])=>k))]
.map(k=>[k,inputArr.filter(([i])=>i===k).map(([k,v])=>v)]).filter(([a])=>
a.endsWith('x') || !inputArr.some(([b])=>b!==a && b.startsWith(a)
)).map((([a,b])=>[a,(a.endsWith('x')?b:
inputArr.filter(([c])=>a.startsWith(c)).map(([c,d])=>d)).join(',')
]))
console.info(outputArr)
Я поражен тем, как вы решили это. Если я хочу удалить хвост «x» в выходном массиве? Таким образом, пятый элемент в выводе будет: ["1.4", "7"]
вместо ["1.4x", "7"]
.
@ImranAlRashid, ты можешь outputArr.map(([k,v])=>[k.replace('x',''),v])
. Или сделайте это как часть моего кода выше, заменив .map((([a,b])=>[a,
на .map((([a,b])=>[a.replace('x',''),
Спасибо! Мне нравится ваш код, потому что он точен. Но у него все еще есть одна проблема, которую нужно решить. Если во входном массиве есть ["1.4x", "7"],["1.4x", "s"],["1.4x", "g"]
, выходной массив должен быть: ["1.4x", ["7","s","g"]]
["1.4x", "7"],["1.4x", "s"],["1.4", "g"]
должен выдать результат ["1.4", "7,s,g"]
. «1,4x», «1,4x», «1,4» следует рассматривать как единое целое.
этот вопрос может вас заинтересовать: stackoverflow.com/questions/75461049/…
Большое спасибо за вашу помощь. Чтобы разместить 3 элемента в подмассивах, я изменил .map((([a,b])
на .map((([a,b,c])
И после .join(',')
добавил: , inputArr.filter(([c])=>a.startsWith(c)).map(([c,d,e])=>e)).join(',')
Можете ли вы предложить более короткое выражение? пример: inputArr=[["1","p","p1"],["1.1","q","q1"]]
outputArr=[["1.1","p,q","p1,q1"]]
Вот общий процесс сокращения разделов:
const inputArr = [
["1", "p"], ["1.1", "q"], ["1.2", "a"], ["1.2", "b"], ["1.2", "c"], ["1.2.1", "d"],
["1.2.2", "4"], ["1.2.2.1", "5"], ["1.3", "6"], ["1.4x", "7"], ["2", "8"],
["2.1", "9"], ["2.2", "10"], ["2.2.1x", "11"], ["2.2.2", "12"], ["3", "13"],
["4", "14"]
];
const rollupSections = (sections, specialSuffix = '', stripSuffix = false) =>
sections
.filter(([id]) =>
id.endsWith(specialSuffix) ||
!sections.some(([subId]) => subId !== id && subId.startsWith(id)))
.map((([id, value]) => [
// Key
specialSuffix && stripSuffix
? id.replace(new RegExp(`${specialSuffix}$`), '')
: id,
// Value
id.endsWith(specialSuffix)
? [value].join(',')
: sections
.filter(([subId]) => id.startsWith(subId))
.map(([, subValue]) => subValue)
.join(',')
]));
const outputArr = rollupSections(inputArr, 'x', true);
outputArr.forEach(pair => console.info(JSON.stringify(pair)));
.as-console-wrapper { top: 0; max-height: 100% !important; }
Вот функциональный пример, который показывает, как выходные данные одной функции могут использоваться в качестве входных данных другой.
const inputArr = [
["1", "p"], ["1.1", "q"], ["1.2", "a"], ["1.2", "b"], ["1.2", "c"], ["1.2.1", "d"],
["1.2.2", "4"], ["1.2.2.1", "5"], ["1.3", "6"], ["1.4x", "7"], ["2", "8"],
["2.1", "9"], ["2.2", "10"], ["2.2.1x", "11"], ["2.2.2", "12"], ["3", "13"],
["4", "14"]
];
const endsWithSpecialSuffix = ([id], specialSuffix) =>
id.endsWith(specialSuffix);
const isChildOf = (id, parentId) => id.startsWith(parentId);
const hasParentSection = ([id], sections) =>
sections.some(([subId]) => subId !== id && isChildOf(subId, id));
const isChildSection = (section, sections, specialSuffix) =>
endsWithSpecialSuffix(section, specialSuffix) ||
!hasParentSection(section, sections)
const childSections = (sections, specialSuffix) =>
sections.filter((section) => isChildSection(section, sections, specialSuffix));
const formatKey = ([id], specialSuffix, stripSuffix) =>
specialSuffix && stripSuffix
? id.replace(new RegExp(`${specialSuffix}$`), '')
: id;
const hasSuffix = (id, specialSuffix) => id.endsWith(specialSuffix);
const formatSubValues = (id, sections) =>
sections
.filter(([subId]) => id.startsWith(subId))
.map(([, subValue]) => subValue)
.join(',');
const formatValue = ([id, value], sections, specialSuffix) =>
hasSuffix(id, specialSuffix)
? [value].join(',')
: formatSubValues(id, sections)
const rollupSections = (sections, specialSuffix = '', stripSuffix = false) =>
childSections(sections, specialSuffix).map(((section) => [
formatKey(section, specialSuffix, stripSuffix),
formatValue(section, sections, specialSuffix)
]))
const outputArr = rollupSections(inputArr, 'x', true);
outputArr.forEach(pair => console.info(JSON.stringify(pair)));
.as-console-wrapper { top: 0; max-height: 100% !important; }
вы действительно должны использовать тот же стиль, что и ОП. шорткод (? :) в любом случае менее читаем.