#javascript #ecmascript-6
Вопрос:
В моем объекте данных есть несколько объектов — необязательно с некоторыми данными зависимостей. Сначала мне нужно получить все элементы с заданным ключом (переданным в виде строкового массива). Для этого первого шага код работает над фильтрацией элементов give.
На первом шаге я фильтрую два из пяти элементов: one
и two
; и ожидаемый результат [«@область/один», «@область/два»].
- Но
@scope/one
естьdeps
ключ, поэтому мне нужно добавитьthree
иtwo
еще к результату.@scope/two
уже существует в результирующем массиве. - И
@scope/three
имеетfour
as deps, который теперь также должен быть добавлен к результату. @scope/four
не имеет депов, поэтому цикл завершен.
В этом примере результат должен быть ['@scope/one', '@scope/two', '@scope/three', '@scope/four']
.
Другими словами: мне нужно отфильтровать некоторые элементы, а затем выполнить цикл для каждого deps и добавить этот ключ также в результирующий массив.
const data = {
'@scope/one': { deps: { three: { foo: 'bar' }, two: { foo: 'bar' } } },
'@scope/two': { foo: 'bar' },
'@scope/three': { deps: { four: { foo: 'bar' } } },
'@scope/four': { foo: 'bar' },
'@scope/five': { foo: 'bar' },
};
function sanitize(data, whitelist) {
return whitelist.reduce(
(result, key) => (data[key] !== undefined ? Object.assign(result, { [key]: data[key] }) : result),
{}
);
}
const filtered = sanitize(data, ['one', 'two']);
const result = Object.keys(filtered);
console.log(result);
Ответ №1:
Поддерживайте очередь ключей и продолжайте нажимать deps
, пока очередь не опустеет:
function pick(obj, keys) {
let res = new Set(), queue = [...keys]
while (queue.length) {
let key = '@scope/' queue.shift()
if (!res.has(key)) {
res.add(key)
let val = obj[key]
if (val.deps)
queue.push(...Object.keys(val.deps))
}
}
return [...res]
}
//
const data = {
'@scope/one': {deps: {three: {foo: 'bar'}, two: {foo: 'bar'}}},
'@scope/two': {foo: 'bar'},
'@scope/three': {deps: {four: {foo: 'bar'}}},
'@scope/four': {deps: {one: {foo: 'bar'}}}, // cycle!
'@scope/five': {foo: 'bar'},
};
console.log(pick(data, ['one', 'two']))
Если возможны циклические зависимости, добавьте if(!res.has(key))
проверку, чтобы разорвать их.
В качестве примечания, это выглядело бы более прозрачно, если deps
бы были просто списки ключей, а не полные объекты.
Комментарии:
1. Спасибо. Я упустил важную вещь: ключи «первого уровня» имеют «область действия» в своем названии, у deps этого нет. В результате мне всегда нужны ключи «первого уровня» с областью действия. Я обновил свой пост.
let val = obj['@scope/' key]
кажется, это не то место… Извините, что пропустил область в первоначальном посте.2. без проблем, одно незначительное изменение:
let key = '@scope/' queue.shift()
3. Я добавил
if(!res.has(key)) res.add(key)
, но циклы по-прежнему бесконечны4. У меня все еще есть бесконечный цикл с моими данными. Я думаю, проблема в том, что мы добавляем в очередь сразу несколько элементов и одновременно удаляем только один элемент. Таким образом, даже если мы проверим наличие существующих элементов в res, может быть несколько циклов, так как для каждого элемента может быть несколько dep.