TLDR; Если поля имеют статус c и вы можете легко перечислить их, оба ваших решения верны почти (см. Ниже объяснение, почему они неверны.) Вот правильный способ сделать это:
result = [
mapped |
original := data[_]
mapped := {"some": original["some"], "another": original.another}
]
Немного более элегантный вариант - определить поля для включения или исключения, как в примере @ eephillip. Например:
result = [
mapped |
original := data[_]
mapped := {k: v |
some k
v := original[k]
not exclude[k]}
]
exclude = {"dont", "dont2"} # defines a SET of keys to exclude
Конечно, вы можете обобщить это еще больше, заставив внутреннее понимание вызвать функцию, которая реализует другие фильтры.
Вот интерактивный пример: https://play.openpolicyagent.org/p/P6wPd3rudJ
Два замечания об исходном решении.
1. result1
не выполняет итерацию по data
правильно
{d |
d := {
"some": data[_].some, # problem: _ is a different variable in each expression
"another": data[_].another
}
}
Концептуально каждое вхождение _
является уникальной переменной. Если вы явно объявите переменные, проблема станет более очевидной:
# note: this is still wrong
{d |
some i, j
d := {
"some": data[i]["some"],
"another": data[j].another
}
}
Если вы запустите это, вы обнаружите, что он производит перекрестный продукт (а это не то, что вам нужно). Вы хотите, чтобы поля "some" и "another" выбирались из одного и того же объекта, подобного этому:
{d |
some i
d := {
"some": data[i]["some"],
"another": data[i].another
}
}
Конечно, поиск уникальных имен переменных может быть проблемой, так что вы можете использовать _
. Только не путайте множественные переменные _
со ссылкой на одно и то же значение. Мы можем переписать оператор для использования _
следующим образом:
{d |
obj := data[_]
d := {
"some": obj["some"],
"another": obj.another
}
}
result2
близко, но может назначать несколько значений (которых следует избегать)
result2 = cleaned {
d := data[_]
cleaned := { # problem: there could be multiple values for 'cleaned'
"some": d["some"],
"another": d.another
}
}
Правила форму NAME = VALUE { BODY }
присвойте VALUE
NAME
, если утверждения в BODY
выполнены. Если вы пропустите BODY
, то есть напишите NAME = VALUE
, тогда BODY
по умолчанию будет true
(что всегда выполняется.)
В приведенном выше примере:
NAME
это result2
VALUE
это cleaned
BODY
это d := data[_]; cleaned := {...}
В Re go, мы Назовите эти правила «полными правилами» . Полные правила - это просто операторы IF-THEN, которые присваивают одно значение переменной. Часть «IF» - это тело правила, а часть «THEN» - это назначение. Следует избегать написания правил, которые могут присваивать значения MULTIPLE одной и той же переменной, поскольку это может привести к ошибке времени оценки. Например:
# do not do this
result = v {
v := data[_] # if 'data' is [1,2,3] then what is the value of 'result'? Hint: There is more than one answer.
}
Если вы хотите присвоить значения MULTIPLE переменной, вы можете определить «частичное правило» Например:
result[v] { # result is a SET.
v := data[_]
}