Обновление
После того, как я написал приведенные ниже решения, я понял, что это действительно можно сделать проще, точно так, как вы предлагали, сопоставляя, а затем уменьшая результат. Это не точно картирование, это скорее извлечение листьев. Но тогда мы можем преобразовать ваш comparatorClassIdToNameMap
в исходный объект вывода и просто уменьшить эти листья в нем.
Хотя приведенный ниже код не является красивым, он действительно решает проблему так, как вы запрашивали, что более чем я могу сказать для решений, которые я впервые написал.
// utility function
const findLeaves = (isLeaf) => (obj) =>
isLeaf (obj)
? [obj]
: Object .values (obj) .flatMap (
(v) => typeof v == 'object' ? findLeaves (isLeaf) (v) : []
)
// main function
const transform = (actvity, nameMapping) => findLeaves (obj => 'PointsPossible' in obj) (activity)
.reduce((
{totalPointsPossible, totalPointsEarned, ...rest},
{PointsPossible, PointsEarned, ComparatorClass},
_, __, // index and array passed to `reduce` are ignored
{PointsPossible: pp, PointsEarned: pe} = rest[nameMapping[ComparatorClass]]
) => ({ // line 7
totalPointsPossible: totalPointsPossible + PointsPossible,
totalPointsEarned: totalPointsEarned + PointsEarned,
...rest,
[nameMapping[ComparatorClass]]: {
PointsPossible: PointsPossible + pp,
PointsEarned: PointsEarned + pe,
ComparatorClassId: ComparatorClass
}
}), // line 16
Object.entries(comparatorClassIdToNameMap).reduce((a, [k, v]) => ({ // line 17
... a,
[v]: {
PointsPossible: 0,
PointsEarned: 0,
ComparatorClassId: Number(k)
}
}), {totalPointsPossible: 0, totalPointsEarned: 0}) // line 24
)
// data
const activity = {Network: {ID: "Network", MLS: {ID: "MLS", Ports: {ID: "Ports", "GigabitEthernet0/1": {ID: "GigabitEthernet0/1", "Port Mode": {ID: "Port Mode", Name: "Port Mode", Value: "0", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 8}, "Native VLAN": {ID: "Native VLAN", Name: "Native VLAN", Value: "99", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 5}}, "GigabitEthernet0/2": {ID: "GigabitEthernet0/2", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "209.165.200.225", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Subnet Mask": {ID: "Subnet Mask", Name: "Subnet Mask", Value: "255.255.255.252", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "(deprecated) IPv6 Addresses": {ID: "Ipv6 Address", "2001: DB8: ACAD: A: : 1": {ID: "2001: DB8: ACAD: A: : 1", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "2001: DB8: ACAD: A: : 1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Prefix Length": {ID: "Prefix", Name: "Prefix Length", Value: "64", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}, SwitchPort: {ID: "SwitchPort", Name: "SwitchPort", Value: "0", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 8}}, Vlan10: {ID: "Vlan10", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "192.168.10.254", PointsPossible: 2, PointsEarned: 2, ComparatorClass: 0}, "(deprecated) IPv6 Addresses": {ID: "Ipv6 Address", "2001: DB8: ACAD: 10: : 1": {ID: "2001: DB8: ACAD: 10: : 1", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "2001: DB8: ACAD: 10: : 1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Prefix Length": {ID: "Prefix", Name: "Prefix Length", Value: "64", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}}, Vlan20: {ID: "Vlan20", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "192.168.20.254", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "(deprecated) IPv6 Addresses": {ID: "Ipv6 Address", "2001: DB8: ACAD: 20: : 1": {ID: "2001: DB8: ACAD: 20: : 1", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "2001: DB8: ACAD: 20: : 1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Prefix Length": {ID: "Prefix", Name: "Prefix Length", Value: "64", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}}, Vlan30: {ID: "Vlan30", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "192.168.30.254", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "(deprecated) IPv6 Addresses": {ID: "Ipv6 Address", "2001: DB8: ACAD: 30: : 1": {ID: "2001: DB8: ACAD: 30: : 1", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "2001: DB8: ACAD: 30: : 1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Prefix Length": {ID: "Prefix", Name: "Prefix Length", Value: "64", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}}, Vlan99: {ID: "Vlan99", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "192.168.99.254", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}, Routes: {ID: "Routes", "Static Routes": {ID: "Static RoutesV2", Name: "Static Routes", Value: "", PointsPossible: 0, PointsEarned: 0, ComparatorClass: 1}, "IP Routing": {ID: "IP Routing", Name: "IP Routing", Value: "1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 1}}, Routesv6: {ID: "Routesv6", "IPv6 Unicast Routing": {ID: "Ipv6 Unicast Routing", Name: "IPv6 Unicast Routing", Value: "1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 1}}, VLANS: {ID: "VLANS", "VLAN 10": {ID: "10", "VLAN Name": {ID: "VLAN Name", Name: "VLAN Name", Value: "Staff", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 5}}, "VLAN 20": {ID: "20", "VLAN Name": {ID: "VLAN Name", Name: "VLAN Name", Value: "Student", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 5}}, "VLAN 30": {ID: "30", "VLAN Name": {ID: "VLAN Name", Name: "VLAN Name", Value: "Faculty", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 5}}}}, S1: {ID: "S1", Ports: {ID: "Ports", "GigabitEthernet0/1": {ID: "GigabitEthernet0/1", "Port Mode": {ID: "Port Mode", Name: "Port Mode", Value: "0", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 8}, "Native VLAN": {ID: "Native VLAN", Name: "Native VLAN", Value: "99", PointsPossible: 2, PointsEarned: 1, ComparatorClass: 5}}}}}};
const comparatorClassIdToNameMap = {0: "Ip", 1: "Routing", 2: "Acl", 3: "Nat", 4: "Physical", 5: "Switching", 6: "Connectivity", 7: "Logical", 8: "All", 9: "Encircling_Head", 10: "Encircling_All"}
// demo
console .log (
transform (activity, comparatorClassIdToNameMap)
)
.as-console-wrapper { max-height: 100% !important; top: 0; }
Строки 17 - 24 создают исходный объект со всеми свойствами, которые вы хотите использовать в выводе, используя comparatorClassIdToNameMap
и добавляя свойства total*
.
Строки 7 - 14 добавляют листовой узел в это. Это происходит внутри reduce
, поэтому все конечные узлы добавляются, а полученный объект возвращается.
Приложение
В комментарии говорится, что вы не очень разбираетесь в JS , Вот альтернативная версия функции выше, написанная в стиле ES5. Этот может быть легче для чтения из других основных языков:
function transform (actvity, nameMapping) {
var baseObj = {totalPointsPossible: 0, totalPointsEarned: 0}
for (var id in nameMapping) {
if (nameMapping .hasOwnProperty (id)) {
var name = nameMapping [id]
baseObj [name] = {
PointsPossible: 0,
PointsEarned: 0,
ComparatorClassId: Number(id)
}
}
}
function isLeaf(obj) {
return 'PointsPossible' in obj
}
var leaves = findLeaves (isLeaf) (activity)
return leaves .reduce (
function (acc, item) {
acc .totalPointsPossible += item .PointsPossible
acc .totalPointsEarned += item .PointsEarned
var key = nameMapping [item .ComparatorClass]
acc [key] .PointsPossible += item .PointsPossible
acc [key] .PointsEarned += item .PointsEarned
return acc
},
baseObj
)
}
Этот делает то же самое, что и выше. Но он полон операторов присваивания, мутации и потока управления - всего, чего я лично стараюсь избегать. Приведенная выше версия позволяет избежать всего этого, используя деструктуризацию и другие более современные методы.
Оригинальное решение
Я больше не рекомендую ни одно из следующих двух предложений, но я думаю, что там в них все еще может быть значение.
Использование библиотеки
Я большой поклонник библиотеки функционального программирования Ramda (отказ от ответственности: я один его основных авторов), и я часто вижу такие проблемы глазами Рамды. Итак, во-первых, решение, которое довольно интенсивно использует Ramda:
// utility function
const findLeaves = (isLeaf) => (obj) =>
isLeaf (obj)
? [obj]
: Object .values (obj) .flatMap (
(v) => typeof v == 'object' ? findLeaves (isLeaf) (v) : []
)
// helper functions
const summarize = pipe (
findLeaves (has('PointsPossible')),
groupBy (prop ('ComparatorClass')),
map ( applySpec ({
PointsPossible: pipe (pluck ('PointsPossible'), sum),
PointsEarned: pipe (pluck ('PointsEarned'), sum),
ComparatorClassID: pipe (head, prop ('ComparatorClass'))
}))
)
const extractTotals = (activity, nameMapping, summary = summarize(activity)) =>
reduce (
(a, [id, name]) =>
({...a, [name]: summary [id] ||
{PointsPossible: 0, PointsEarned: 0, ComparatorClassID: id}}),
{},
toPairs (nameMapping)
)
// main function
const transform = (activity, nameMapping, totals = extractTotals (activity, nameMapping)) =>
Object .assign (applySpec ({
totalPointsPossible: pipe (pluck ('PointsPossible'), sum),
totalPointsEarned: pipe (pluck ('PointsEarned'), sum),
}) (values (totals)), totals)
// data
const activity = {Network: {ID: "Network", MLS: {ID: "MLS", Ports: {ID: "Ports", "GigabitEthernet0/1": {ID: "GigabitEthernet0/1", "Port Mode": {ID: "Port Mode", Name: "Port Mode", Value: "0", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 8}, "Native VLAN": {ID: "Native VLAN", Name: "Native VLAN", Value: "99", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 5}}, "GigabitEthernet0/2": {ID: "GigabitEthernet0/2", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "209.165.200.225", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Subnet Mask": {ID: "Subnet Mask", Name: "Subnet Mask", Value: "255.255.255.252", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "(deprecated) IPv6 Addresses": {ID: "Ipv6 Address", "2001: DB8: ACAD: A: : 1": {ID: "2001: DB8: ACAD: A: : 1", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "2001: DB8: ACAD: A: : 1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Prefix Length": {ID: "Prefix", Name: "Prefix Length", Value: "64", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}, SwitchPort: {ID: "SwitchPort", Name: "SwitchPort", Value: "0", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 8}}, Vlan10: {ID: "Vlan10", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "192.168.10.254", PointsPossible: 2, PointsEarned: 2, ComparatorClass: 0}, "(deprecated) IPv6 Addresses": {ID: "Ipv6 Address", "2001: DB8: ACAD: 10: : 1": {ID: "2001: DB8: ACAD: 10: : 1", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "2001: DB8: ACAD: 10: : 1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Prefix Length": {ID: "Prefix", Name: "Prefix Length", Value: "64", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}}, Vlan20: {ID: "Vlan20", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "192.168.20.254", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "(deprecated) IPv6 Addresses": {ID: "Ipv6 Address", "2001: DB8: ACAD: 20: : 1": {ID: "2001: DB8: ACAD: 20: : 1", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "2001: DB8: ACAD: 20: : 1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Prefix Length": {ID: "Prefix", Name: "Prefix Length", Value: "64", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}}, Vlan30: {ID: "Vlan30", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "192.168.30.254", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "(deprecated) IPv6 Addresses": {ID: "Ipv6 Address", "2001: DB8: ACAD: 30: : 1": {ID: "2001: DB8: ACAD: 30: : 1", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "2001: DB8: ACAD: 30: : 1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Prefix Length": {ID: "Prefix", Name: "Prefix Length", Value: "64", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}}, Vlan99: {ID: "Vlan99", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "192.168.99.254", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}, Routes: {ID: "Routes", "Static Routes": {ID: "Static RoutesV2", Name: "Static Routes", Value: "", PointsPossible: 0, PointsEarned: 0, ComparatorClass: 1}, "IP Routing": {ID: "IP Routing", Name: "IP Routing", Value: "1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 1}}, Routesv6: {ID: "Routesv6", "IPv6 Unicast Routing": {ID: "Ipv6 Unicast Routing", Name: "IPv6 Unicast Routing", Value: "1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 1}}, VLANS: {ID: "VLANS", "VLAN 10": {ID: "10", "VLAN Name": {ID: "VLAN Name", Name: "VLAN Name", Value: "Staff", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 5}}, "VLAN 20": {ID: "20", "VLAN Name": {ID: "VLAN Name", Name: "VLAN Name", Value: "Student", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 5}}, "VLAN 30": {ID: "30", "VLAN Name": {ID: "VLAN Name", Name: "VLAN Name", Value: "Faculty", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 5}}}}, S1: {ID: "S1", Ports: {ID: "Ports", "GigabitEthernet0/1": {ID: "GigabitEthernet0/1", "Port Mode": {ID: "Port Mode", Name: "Port Mode", Value: "0", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 8}, "Native VLAN": {ID: "Native VLAN", Name: "Native VLAN", Value: "99", PointsPossible: 2, PointsEarned: 1, ComparatorClass: 5}}}}}};
const comparatorClassIdToNameMap = {0: "Ip", 1: "Routing", 2: "Acl", 3: "Nat", 4: "Physical", 5: "Switching", 6: "Connectivity", 7: "Logical", 8: "All", 9: "Encircling_Head", 10: "Encircling_All"}
// demo
console .log (
transform (activity, comparatorClassIdToNameMap)
)
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script>
const {pipe, has, groupBy, prop, map, applySpec, pluck, sum, head, reduce, toPairs, values} = R
</script>
Наша основная функция transform
зависит от extractTotals
, который зависит от summarize
, который, в свою очередь, зависит от findLeaves
. Очевидно, что поскольку extractTotals
и summarize
используются только для внутреннего использования, вы можете усвоить их внутри друг друга; Я бы не рекомендовал это. И findLeaves
является рекурсивным, поэтому не может быть обработан таким образом.
findLeaves
принимает функцию предиката, чтобы проверить, является ли узел листом и объектом, и рекурсивно находит все узлы, о которых сообщается, что листья. Он не обрабатывает массивы, но это не было частью ваших требований; расширение не составит труда.
Если мы вызовем findLeaves(obj => 'PointsPossible' in obj)(activity)
, мы получим плоский массив, содержащий все конечные узлы, например:
[
{
"ID": "Port Mode",
"Name": "Port Mode",
"Value": "0",
"PointsPossible": 1,
"PointsEarned": 1,
"ComparatorClass": 8
},
{
"ID": "Native VLAN",
"Name": "Native VLAN",
"Value": "99",
"PointsPossible": 1,
"PointsEarned": 1,
"ComparatorClass": 5
},
// ...
]
summarize
использует findLeaves
и ряд функций Ramda, превращающих ваш activity
в
{
"0": {
"PointsPossible": 15,
"PointsEarned": 15,
"ComparatorClassID": 0
},
"1": {
"PointsPossible": 2,
"PointsEarned": 2,
"ComparatorClassID": 1
},
// ...
}
Мы получаем почти весь путь с extractTotals
, который сочетает в себе вышеупомянутое с вашим comparatorClassIdToNameMap
, чтобы получить это:
{
"Ip": {
"PointsPossible": 15,
"PointsEarned": 15,
"ComparatorClassID": 0
},
"Routing": {
"PointsPossible": 2,
"PointsEarned": 2,
"ComparatorClassID": 1
},
// ...
}
Единственное, чего не хватает, это общих итогов. Это остается для transform
, который берет результат вышеупомянутого и добавляет эти итоговые значения к результирующему объекту:
{
"totalPointsPossible": 26,
"totalPointsEarned": 25,
"Ip": {
"PointsPossible": 15,
"PointsEarned": 15,
"ComparatorClassID": 0
},
"Routing": {
"PointsPossible": 2,
"PointsEarned": 2,
"ComparatorClassID": 1
},
// ...
}
( Примечание , что здесь нет ничего, чтобы обрабатывать ваши itemsComplete
или itemsPossible
. Я не вижу в данных ничего, что могло бы помочь с этим, но я предполагаю, что это были бы простые дополнения к описанному выше.)
Эта проблема является моей обычной техникой выполнения. небольшие преобразования по одному, всегда пытаясь приблизиться к требуемому решению. Там могут быть полезные способы объединить шаги. Я оставляю это вам.
Без библиотеки
В такой библиотеке, как Рамда, нет магов c. Мы можем написать повторно используемые версии его функций самостоятельно. И это часто улучшает многие части нашего кода.
Итак, мы могли бы сделать то же самое самостоятельно, написав собственную версию этих функций Ramda. Большинство тривиально. Только applySpec
, groupBy
и mapObj
имеют любую сложность. Обратите внимание, что в вышеприведенной версии Ramda мы использовали map
вместо Рамады mapObj
. Хотя мы могли бы написать map
для обработки массивов или объектов, здесь проще сделать две функции.
// utility functions
const pipe = (...fns) => (arg) =>
fns.reduce((a, fn) => fn(a), arg)
const map = (fn) => (xs) =>
xs .map (x => fn (x))
const mapObj = (fn) => (obj) =>
Object .fromEntries (map (([k, v]) => [k, fn (v)]) (Object .entries (obj)))
const has = (name) => (obj) =>
name in obj
const prop = (name) => (obj) =>
obj [name]
const pluck = (name) =>
map (prop (name))
const head = (xs) =>
xs [0]
const sum = (ns) =>
ns .reduce ((a, b) => a + b, 0)
const applySpec = (spec) => (obj) =>
Object .entries (spec) .reduce ((a, [k, fn]) => ({...a, [k]: fn (obj)}), {})
const groupBy = (fn) => (xs) =>
xs .reduce ((a, x, _, __, k = fn(x)) => ({...a, [k]: [...(a[k] || []), x]}), {})
const findLeaves = (isLeaf) => (obj) =>
isLeaf (obj)
? [obj]
: Object .values (obj) .flatMap (
(v) => typeof v == 'object' ? findLeaves (isLeaf) (v) : []
)
// helper functions
const summarize = pipe (
findLeaves (has ('PointsPossible')),
groupBy (prop ('ComparatorClass')),
mapObj ( applySpec ({
PointsPossible: pipe (pluck ('PointsPossible'), sum),
PointsEarned: pipe (pluck ('PointsEarned'), sum),
ComparatorClassID: pipe (head, prop ('ComparatorClass'))
}))
)
const extractTotals = (activity, nameMapping, summary = summarize(activity)) =>
Object .entries (nameMapping)
.reduce (
(a, [id, name]) => ({...a, [name]: summary[id] || {PointsPossible: 0, PointsEarned: 0, ComparatorClassID: id}}),
{}
)
// main function
const transform = (activity, nameMapping) => {
const totals = extractTotals (activity, nameMapping)
return Object .assign (applySpec ({
totalPointsPossible: pipe (pluck ('PointsPossible'), sum),
totalPointsEarned: pipe (pluck ('PointsEarned'), sum),
}) (Object .values (totals)), totals)
}
// data
const activity = {Network: {ID: "Network", MLS: {ID: "MLS", Ports: {ID: "Ports", "GigabitEthernet0/1": {ID: "GigabitEthernet0/1", "Port Mode": {ID: "Port Mode", Name: "Port Mode", Value: "0", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 8}, "Native VLAN": {ID: "Native VLAN", Name: "Native VLAN", Value: "99", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 5}}, "GigabitEthernet0/2": {ID: "GigabitEthernet0/2", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "209.165.200.225", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Subnet Mask": {ID: "Subnet Mask", Name: "Subnet Mask", Value: "255.255.255.252", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "(deprecated) IPv6 Addresses": {ID: "Ipv6 Address", "2001: DB8: ACAD: A: : 1": {ID: "2001: DB8: ACAD: A: : 1", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "2001: DB8: ACAD: A: : 1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Prefix Length": {ID: "Prefix", Name: "Prefix Length", Value: "64", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}, SwitchPort: {ID: "SwitchPort", Name: "SwitchPort", Value: "0", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 8}}, Vlan10: {ID: "Vlan10", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "192.168.10.254", PointsPossible: 2, PointsEarned: 2, ComparatorClass: 0}, "(deprecated) IPv6 Addresses": {ID: "Ipv6 Address", "2001: DB8: ACAD: 10: : 1": {ID: "2001: DB8: ACAD: 10: : 1", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "2001: DB8: ACAD: 10: : 1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Prefix Length": {ID: "Prefix", Name: "Prefix Length", Value: "64", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}}, Vlan20: {ID: "Vlan20", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "192.168.20.254", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "(deprecated) IPv6 Addresses": {ID: "Ipv6 Address", "2001: DB8: ACAD: 20: : 1": {ID: "2001: DB8: ACAD: 20: : 1", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "2001: DB8: ACAD: 20: : 1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Prefix Length": {ID: "Prefix", Name: "Prefix Length", Value: "64", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}}, Vlan30: {ID: "Vlan30", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "192.168.30.254", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "(deprecated) IPv6 Addresses": {ID: "Ipv6 Address", "2001: DB8: ACAD: 30: : 1": {ID: "2001: DB8: ACAD: 30: : 1", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "2001: DB8: ACAD: 30: : 1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}, "Prefix Length": {ID: "Prefix", Name: "Prefix Length", Value: "64", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}}, Vlan99: {ID: "Vlan99", "IP Address": {ID: "IP Address", Name: "IP Address", Value: "192.168.99.254", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 0}}}, Routes: {ID: "Routes", "Static Routes": {ID: "Static RoutesV2", Name: "Static Routes", Value: "", PointsPossible: 0, PointsEarned: 0, ComparatorClass: 1}, "IP Routing": {ID: "IP Routing", Name: "IP Routing", Value: "1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 1}}, Routesv6: {ID: "Routesv6", "IPv6 Unicast Routing": {ID: "Ipv6 Unicast Routing", Name: "IPv6 Unicast Routing", Value: "1", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 1}}, VLANS: {ID: "VLANS", "VLAN 10": {ID: "10", "VLAN Name": {ID: "VLAN Name", Name: "VLAN Name", Value: "Staff", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 5}}, "VLAN 20": {ID: "20", "VLAN Name": {ID: "VLAN Name", Name: "VLAN Name", Value: "Student", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 5}}, "VLAN 30": {ID: "30", "VLAN Name": {ID: "VLAN Name", Name: "VLAN Name", Value: "Faculty", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 5}}}}, S1: {ID: "S1", Ports: {ID: "Ports", "GigabitEthernet0/1": {ID: "GigabitEthernet0/1", "Port Mode": {ID: "Port Mode", Name: "Port Mode", Value: "0", PointsPossible: 1, PointsEarned: 1, ComparatorClass: 8}, "Native VLAN": {ID: "Native VLAN", Name: "Native VLAN", Value: "99", PointsPossible: 2, PointsEarned: 1, ComparatorClass: 5}}}}}};
const comparatorClassIdToNameMap = {0: "Ip", 1: "Routing", 2: "Acl", 3: "Nat", 4: "Physical", 5: "Switching", 6: "Connectivity", 7: "Logical", 8: "All", 9: "Encircling_Head", 10: "Encircling_All"}
// demo
console .log (
transform (activity, comparatorClassIdToNameMap)
)
.as-console-wrapper { max-height: 100% !important; top: 0; }
Здесь используется та же разбивка проблемы, что и выше, просто пишется пользовательская версия функций Ramda. Если вы хотите узнать больше о каком-либо из них (кроме mapObj
, который в Ramda указан как map
), см. Документацию Ramda . Эти реализации проще, чем у Ramda, и, как правило, менее гибкие, но они работают для наших случаев.
Примечание
Мне показалось, что это интересная проблема, которую стоит попробовать. Но я почти сразу сдался из-за стены данных. Очень трудно пролистать столько данных, чтобы попытаться определить требования. В следующий раз просмотрите Как создать минимальный воспроизводимый пример перед публикацией. Вы должны быть в состоянии сделать намного меньший контрольный пример, который все еще демонстрирует цель.