映射数组中的项目
Mapping items in an array
希望这是一个简单的好方法,但我不知道该怎么做。
我想使用 rego 将数组中的项目映射到更清晰的版本。例如从下面的数据
data = [
{
"some": "value",
"another": "mvalue",
"dont": "want"
},
{
"some": "value1",
"another": "mvalue1",
"dont": "want1"
},
{
"some": "value2",
"another": "mvalue2",
"dont": "want2"
}
]
我想把数据变成
result = [
{
"some": "value",
"another": "mvalue"
},
{
"some": "value1",
"another": "mvalue1"
},
{
"some": "value2",
"another": "mvalue2"
}
]
我认为最接近的两个是
result1 = cleaned {
cleaned := {d |
d := {
"some": data[_].some,
"another": data[_].another
}
}
}
result2 = cleaned {
d := data[_]
cleaned := {
"some": p.some,
"another": p.another
}
}
在理解过程中拒绝键名怎么样?
可能是一种更优雅的方法,但可能会有所帮助。
package play
reject(key) = result {
remove := [ "dont", "someotherthing" ]
result := key == remove[_]
}
result = d {
d := [ obj |
val := input.data[_];
obj := { k: v |
v := val[k]
not reject(k)
}
]
}
TLDR;如果字段是静态的并且您可以轻松地枚举它们,那么您的两个解决方案 几乎 都是正确的(请参阅下文了解它们为何不正确的解释。)这是正确的方法:
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
}
}
如果满足 BODY
中的语句,NAME = VALUE { BODY }
形式的规则将 VALUE
分配给 NAME
。如果省略 BODY
,即写 NAME = VALUE
,则 BODY
默认为 true
(始终满足。)
在你上面的例子中:
NAME
是 result2
VALUE
是 cleaned
BODY
是 d := data[_]; cleaned := {...}
在 Rego 中,我们称这些规则为 "complete rules"。完整的规则只是将单个值分配给变量的 IF-THEN 语句。 "IF" 部分是规则主体,"THEN" 部分是赋值。您应该避免编写可能将多个值分配给同一变量的规则,因为这可能会导致评估时间错误。例如:
# 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.
}
如果你想为一个变量分配多个值,那么你可以定义一个 "partial rule" 例如:
result[v] { # result is a SET.
v := data[_]
}
希望这是一个简单的好方法,但我不知道该怎么做。
我想使用 rego 将数组中的项目映射到更清晰的版本。例如从下面的数据
data = [
{
"some": "value",
"another": "mvalue",
"dont": "want"
},
{
"some": "value1",
"another": "mvalue1",
"dont": "want1"
},
{
"some": "value2",
"another": "mvalue2",
"dont": "want2"
}
]
我想把数据变成
result = [
{
"some": "value",
"another": "mvalue"
},
{
"some": "value1",
"another": "mvalue1"
},
{
"some": "value2",
"another": "mvalue2"
}
]
我认为最接近的两个是
result1 = cleaned {
cleaned := {d |
d := {
"some": data[_].some,
"another": data[_].another
}
}
}
result2 = cleaned {
d := data[_]
cleaned := {
"some": p.some,
"another": p.another
}
}
在理解过程中拒绝键名怎么样? 可能是一种更优雅的方法,但可能会有所帮助。
package play
reject(key) = result {
remove := [ "dont", "someotherthing" ]
result := key == remove[_]
}
result = d {
d := [ obj |
val := input.data[_];
obj := { k: v |
v := val[k]
not reject(k)
}
]
}
TLDR;如果字段是静态的并且您可以轻松地枚举它们,那么您的两个解决方案 几乎 都是正确的(请参阅下文了解它们为何不正确的解释。)这是正确的方法:
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
}
}
如果满足 BODY
中的语句,NAME = VALUE { BODY }
形式的规则将 VALUE
分配给 NAME
。如果省略 BODY
,即写 NAME = VALUE
,则 BODY
默认为 true
(始终满足。)
在你上面的例子中:
NAME
是result2
VALUE
是cleaned
BODY
是d := data[_]; cleaned := {...}
在 Rego 中,我们称这些规则为 "complete rules"。完整的规则只是将单个值分配给变量的 IF-THEN 语句。 "IF" 部分是规则主体,"THEN" 部分是赋值。您应该避免编写可能将多个值分配给同一变量的规则,因为这可能会导致评估时间错误。例如:
# 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.
}
如果你想为一个变量分配多个值,那么你可以定义一个 "partial rule" 例如:
result[v] { # result is a SET.
v := data[_]
}