In OPA it's clear how to query against condition AND condition:
values := {
"value1": {
"a": "one"
},
"value2": {
"a": "one",
"b": "two"
},
"value3": {
"a": "one",
"b": "one"
}
}
goodValues = [name |
value = values[name]
value.a == "one"
value.b == "one"
]
So that goodValues here will contain value3 only.
But how to query condition OR condition, so that goodValues will contain all 3 values, because they have either value.a == "one" OR value.b == "one"?
Joining multiple expressions together expresses logical AND. To express logical OR you define multiple rules or functions with the same name. There are a couple different ways this can work. This is covered in the introduction to OPA: https://www.openpolicyagent.org/docs/latest/#logical-or.
Option 1: Comprehensions & Functions
The conditions that you want to express against the value can be factored into helper functions and then the comprehension query can refer to the function.
goodValues = [name |
value := values[name]
value_match(value)
]
value_match(v) {
v.a == "one"
}
value_match(v) {
v.b = "two"
}
Option 2: Incremental Rules
In OPA/Rego, incremental rules assign a set of values to a variable. The rule definition provides the logic to generate the set values. Unlike comprehensions, you can overload the rule definition (providing multiple with the same name) and express logical OR like the other answer explains.
# goodValues is a set that contains 'name' if...
goodValues[name] {
value := values[name] # name is in values
value.a == "one" # value.a is "one"
}
# goodvalues is a set that contains 'name' if...
goodValues[name] {
value := values[name] # name is in values
value.b == "two" # value.b is "two"
}
Found an ugly answer so far, via incremental set:
goodValues[name] {
value = values[name]
value.a == "one"
}
goodValues[name] {
value = values[name]
value.b == "one"
}
But what if that common condition value = values[name] gets more complicated? Will need to extract it to a separate variable (and iterate over that in every condition statement)? Any better solution?
Related
I want to know how this work it should remove the item in list number 3 which is 'four' and print 'one','two','Three' why it is print three, four
here is the code:
final numbers = <String>['one', 'two', 'three', 'four'];
numbers.removeWhere((item) => item.length == 3);
print(numbers); // [three, four]`
removeWhere :Removes all objects from this list that satisfy test.
An object o satisfies test if test(o) is true.
removeWhere will go through the list and find the matched item, means where we do our logic and return true.
You can see item.length==3 is true for 'one' and 'two' because its string length is 3, that's why these elements are removed. You can find more on List
You can expand the method like
numbers.removeWhere((item) {
bool isItemContains3Char = item.length == 3;
print("${isItemContains3Char} : $item length : ${item.length}");
return isItemContains3Char;
});
All you need to return true based on your logic from removeWhere to remove elements.
final numbers = <String>['one', 'two', 'three', 'four'];
numbers.removeAt(2);
print(numbers);
output
[one, two, four]
There is a nested hash, I need to find the first level key by the key inside of it. For instance,
hash = {
a: {
first: 0,
second: 1
},
b: {
third: 2
}
}
I am given :first and I need to find the key it belongs to, in this case it would be :a . Thanks in advance
If you wish to interrogate the hash multiple times, for different inner keys (:first, :second, and so on) you may wish to construct the following hash before the interrogations begin.
hash = { a: { first: 0, second: 1 }, b: { third: 2 } }
h = hash.each_with_object({}) { |(k,v),h| v.each { |kk,_| h[kk] = k } }
#=> {:first=>:a, :second=>:a, :third=>:b}
so that later you may simply do hash lookups:
h[:first]
#=> :a
If the hash could look like this:
hash = { a: { first: 0, second: 1 }, b: { third: 2, first: 3 } }
you may wish to define h as follows:
h = hash.each_with_object({}) do |(k,v),h|
v.each { |kk,_| h.update(kk=>[k]) { |_,o,n| o+n } }
end
#=> {:first=>[:a, :b], :second=>[:a], :third=>[:b]}
This uses the form of Hash#update (a.k.a. merge!) that employs a block (here { |_,o,n| o+n }) to determine the values of keys that are present in both hashes being merged. See the doc for explanations of the three block variables _, o and n. I used _ for the variable holding the common key to tell the reader that it is not used in the block calculations. That is common practice, though you might see, for example, _key in place of _.
You can use Enumerable#find and Hash#key?:
Hash[*hash.find { |_, value| value.key?(:first) }]
# {:a=>{:first=>0, :second=>1}}
Really, being a Hash it's possible you can have the same key in different hashes within the "main" hash, so probably select is an option as well.
You can extract the keys and then find the one for which hash has a key named :first:
hash.keys.find { |k| hash[k].key?(:first) }
#=> :a
Use select instead of find to get an array of all matching keys (if there can be multiple).
I'm using json-compare gem to compare two different json files.
Example file 1:
{"suggestions": [
{
"id1": 1,
"title1": "Test",
"body1": "Test"
}
]
}
Example file 2:
{"suggestions": [
{
"id2": 1,
"title2": "Test",
"body2": "Test"
}
]
}
The gem works well and spits out a hash that looks like this:
{:update=>
{"suggestions" =>
{:update=>
{0=>
{:append=>
{"id2"=>1, "title2"=>"Test", "body2"=>"Test"},
:remove=>
{"id1"=>1, "title1"=>"Test", "body1"=>"Test"},
}
}
}
}
}
How can I parse this and return all the places where json Keys were changed? For the sake of simplicity, how would I put to the console:
id1 changed to id2
title1 changed to title2
body1 changed to body2
For the purpose of what I'm building I don't need to know changes to the values. I just need to know that id1 became id2, etc.
Except if you are relaying on key ordering there is no way to tell that id1 got replaced by id2 and title2 by title1, or that id1 became title1 and id2 became title2. Sounds like you would need specific logic related to the actual key names (in this example searching for different integer suffixes).
Maybe this can be enough for the purpose:
def find_what_changed_in(mhash, result = [])
result << mhash
return if mhash.keys == [:append, :remove]
mhash.keys.each { |k| find_what_changed_in(mhash[k], result) }
result.last
end
find_what_changed_in(changes)
#=> {:append=>{"id2"=>1, "title2"=>"Test", "body2"=>"Test"}, :remove=>{"id1"=>1, "title1"=>"Test", "body1"=>"Test"}}
Where:
changes = {:update=>
{"suggestions" =>
{:update=>
{0=>
{:append=>
{"id2"=>1, "title2"=>"Test", "body2"=>"Test"},
:remove=>
{"id1"=>1, "title1"=>"Test", "body1"=>"Test"},
...
Is this script:
local data =
{
{ "data1", "1"},
{ "data5", "2"},
{ "3453453", "3"},
{ "zzz", "4"},
{ "222", "5"},
{ "lol", "6"},
{ "asdf", "7"},
{ "hello", "8"},
}
local function test()
local count = #data
for i = 1, count do
print(data[i][1] .. " = " .. data[i][2])
end
end
test()
Guaranteed to output:
data1 = 1
data5 = 2
3453453 = 3
zzz = 4
222 = 5
lol = 6
asdf = 7
hello = 8
If not then why, and what is best way performance wise to make it so?
I read something about pairs VS ipairs not returning a fixed order of results
ipairs is an iterator of the array elements of a table, in order from first to last. "Array elements" being defined as the members of a table with keys that are numeric values on the range [1, #tbl], where #tbl is the length operator applied to the table.
pairs is an iterator over all of the elements of a table: array and non-array elements alike. Non-array elements of a table have no intrinsic order to Lua, so pairs will return them in any order. And even though the array elements do technically have an order, pairs will not make an exception for them; it always operates in an arbitrary order.
Your code works like ipairs: iterating over each of the numeric keys of the table from 1 to its length.
The following code prints:
false
false
true
{{a: b}, {a: b}}
code
import "dart:json" as JSON;
main() {
print(JSON.parse('{ "a" : "b" }') == JSON.parse('{ "a" : "b" }'));
print({ "a" : "b" } == { "a" : "b" });
print({ "a" : "b" }.toString() == { "a" : "b" }.toString());
Set s = new Set();
s.add(JSON.parse('{ "a" : "b" }'));
s.add(JSON.parse('{ "a" : "b" }'));
print(s);
}
I am using json and parsing two equivalent objects, storing them in a Set, hoping they will not be duplicated. This is not the case and it seems to be because the first two lines (unexpectedly?) results in false. What is an efficient way to correctly compare two Map objects assuming each were the result of JSON.parse()?
The recommended way to compare JSON maps or lists, possibly nested, for equality is by using the Equality classes from the following package
import 'package:collection/collection.dart';
E.g.,
Function eq = const DeepCollectionEquality().equals;
var json1 = JSON.parse('{ "a" : 1, "b" : 2 }');
var json2 = JSON.parse('{ "b" : 2, "a" : 1 }');
print(eq(json1, json2)); // => true
For details see this answer which talks about some of the different equality classes: How can I compare Lists for equality in Dart?.
This is a difficult one, because JSON objects are just Lists and Maps of num, String, bool and Null. Testing Maps and Lists on equality is still an issue in Dart, see https://code.google.com/p/dart/issues/detail?id=2217
UPDATE
This answer is not valid anymore, see answer #Patrice_Chalin
This is actually pretty hard, as the == operator on Maps and Lists doesn't really compare keys/values/elements to each other.
Depending on your use case, you may have to write a utility method. I once wrote this quick and dirty function:
bool mapsEqual(Map m1, Map m2) {
Iterable k1 = m1.keys;
Iterable k2 = m2.keys;
// Compare m1 to m2
if(k1.length!=k2.length) return false;
for(dynamic o in k1) {
if(!k2.contains(o)) return false;
if(m1[o] is Map) {
if(!(m2[o] is Map)) return false;
if(!mapsEqual(m1[o], m2[o])) return false;
} else {
if(m1[o] != m2[o]) return false;
}
}
return true;
}
Please note that while it handles nested JSON objects, it will always return false as soon as nested lists are involved. If you want to use this approach, you may need to add code for handling this.
Another approach I once started was to write wrappers for Map and List (implementing Map/List to use it normally) and override operator==, then use JsonParser and JsonListener to parse JSON strings using those wrappers. As I abandoned that pretty soon, I don't have code for it and don't know if it really would have worked, but it could be worth a try.
The matcher library, used from unittest, will do this.