Having the code:
def res = [:].withDefault{ 0 }
someList.each{ res[ it ] += getFreq( it ) }
I want to remove the defaulting of the values, so that the call res[ 33 ] doesn't insert the new pair.
The MapWithDefault does not seem to have an accessor to the delegate. Sledgehammer: res.#delegate
as easy as assign the donor to another var:
def original = [:]
def res = original.withDefault{ 0 }
someList.each{ res[ it ] += getFreq( it ) }
assert null == orininal[ 333 ]
assert 0 == res[ 333 ]
assert 0 == orininal[ 333 ]
I realize that you are using withDefault() to make your += expression self-initializing. However, in such cases I generally prefer to do that initialization on the fly using the elvis ?: operator:
def res = [:]
res.getMetaClass().putMoreFreq = { res[ it ] = (res[ it ] ?: 0) + getFreq( it ) }
someList.each{ res.putMoreFreq(it) }
assert null == res[ 333 ]
If you find this answer to be non-responsive, I'll be happy to take it down.
EDIT: with code changes as suggested in comments.
Related
For debugging purposes before writing out tests, I am looking to get the number of key:value pairs within the one object in the array.
Right now, I have this:
"items": [
{
"id": "6b0051ad-721d-blah-blah-4dab9cf39ff4",
"external_id": "blahvekmce",
"filename": "foo-text_field-XYGLVU",
"created_date": "2019-02-11T04:10:31Z",
"last_update_date": "2019-02-11T04:10:31Z",
"file_upload_date": "2019-02-11T04:10:31Z",
"deleted_date": null,
"released_and_not_expired": true,
"asset_properties": null,
"file_properties": null,
"thumbnails": null,
"embeds": null
}
]
When I write out:
* print response.items.length // returns 1
When I write out:
* print response.items[0].length it doesn't return anything
Any thoughts on how I can approach this?
There are multiple ways, but this should work, plus you see how to get the keys as well:
* def keys = []
* eval karate.forEach(response.items[0], function(x){ keys.add(x) })
* def count = keys.length
* match count == 12
Refer the docs: https://github.com/intuit/karate#json-transforms
Karate now provides karate.sizeOf() API to get count of an object.
* def object = { a: 1, b: 'hello' }
* def count = karate.sizeOf(object)
* match count == 2
Ref: https://github.com/karatelabs/karate#the-karate-object
count = 0
for (var v in response.items[0]) {
count = count + 1;
}
print(count)
For example, is posible to do something like this (this fails):
def map = [ property: 1,
propertyPlusOne: map.property + 1]
Of course, it's posible to do so:
def map = [:]
map.property = 1
map.propertyPlusOne = map.property + 1
But all in the declaration?
You could use a with declaration:
def map = [ : ].with {
property = 1
propertyPlusOne = property + 1
it
}
assert map.propertyPlusOne == 2
Though something like ruby's tap (or #timyates' extension) is slightly cleaner:
def map = [ : ].tap {
property = 1
propertyPlusOne = property + 1
}
assert map.propertyPlusOne == 2
Generally not.
You have to define and initialize your map var first, to be able to set values:
def map = [ property: 1 ]
map += [ propertyPlusOne: map.property + 1]
I'm not sure what you are up to, but it might be worth checking the withDefault() method.
I have an existing map in Groovy.
I want to create a new map that has the same keys but different values in it.
Eg.:
def scores = ["vanilla":10, "chocolate":9, "papaya": 0]
//transformed into
def preference = ["vanilla":"love", "chocolate":"love", "papaya": "hate"]
Any way of doing it through some sort of closure like:
def preference = scores.collect {//something}
You can use collectEntries
scores.collectEntries { k, v ->
[ k, 'new value' ]
}
An alternative to using a map for the ranges would be to use a switch
def grade = { score ->
switch( score ) {
case 10..9: return 'love'
case 8..6: return 'like'
case 5..2: return 'meh'
case 1..0: return 'hate'
default : return 'ERR'
}
}
scores.collectEntries { k, v -> [ k, grade( v ) ] }
Nice, functional style solution(including your ranges, and easy to modify):
def scores = [vanilla:10, chocolate:9, papaya: 0]
// Store somewhere
def map = [(10..9):"love", (8..6):"like", (5..2):"meh", (1..0):"hate"]
def preference = scores.collectEntries { key, score -> [key, map.find { score in it.key }.value] }
// Output: [vanilla:love, chocolate:love, papaya:hate]
def scores = ["vanilla":10, "chocolate":9, "papaya": 0]
def preference = scores.collectEntries {key, value -> ["$key":(value > 5 ? "like" : "hate")]}
Then the result would be
[vanilla:like, chocolate:like, papaya:hate]
EDIT: If you want a map, then you should use collectEntries like tim_yates said.
I am trying to count string values in a member of an object. I have tried three ways, but only one works. I am fine with the one that works, but I can't understand why the others fail. Here's the code:
void testCount() {
TestObj a = new TestObj()
TestObj b = new TestObj()
TestObj c = new TestObj()
a.s = "one"
b.s = "two"
c.s = "two"
def list = [a, b, c]
def count = 0
list.each{
if (it.s.equals("two"))
count++
}
assertTrue("each test failed", count == 2)
assertTrue("collectAll test failed", list.collectAll{ it.s.equals("two")}.size() == 2)
assertTrue("count test failed", list.count{ it.s.equals("two")} == 2)
}
I would expect the Closures passed to collectAll and count to do the same thing I'm doing in my each method. But in the case of collectAll it returns all 3 of the objects and in the case of count it always returns 0.
What am I missing?
collectAll is recursively going through your list, and returning a boolean (as that is what your closure returns for each element in the List)...
So, you get [ false, true, true ], which has 3 elements...
For count,
list.count{ it.s == "two" }
Returns 2 (as expected)
btw: you can do it.s == 'two' in groovy.. no need for all the .equals( "two" )
Edit... Example for count:
class TestObj {
String s
}
list = [ new TestObj( s:'one' ), new TestObj( s:'two' ), new TestObj( s:'two' ) ]
println( list.count { it.s == 'two' } )
Prints 2 for me...
edit 2
Found the cause (from comment below), count didn't accept a closure as a parameter till 1.8 so you'll be calling the object version which will tell you how many times an instance of the closure exists in the list (which is none, as it says)
I'm trying to have a good access to multi-dimensional arrays with string indexes in Lua, here's basically what I'm trying to do:
rules =
{
{"S_RIGHT", "A_STOP", "S_RESULT"},
}
matrix = {}
for _,v in pairs(rules) do
if( matrix[ v[1] ] == nil ) then
matrix[ v[1] ] = {}
end
matrix[ v[1] ][ v[2] ] = v[3]
end
-- results in error ( attempt to index field 'S_NO' a nil value)
var = matrix["S_NO"]["S_RESULT"]
assert(var == nil, "Var should be nil")
A way to do it but quite verbose is:
var = matrix["S_NO"]
if var ~= nil then
var = var["S_RESULT"]
end
assert(var == nil, "Var should be nil")
Is there a way to make the first case to work ? ( less verbose )
Ok,
Found the answer.
If matrix is going to be read-only a correct approach would be:
local empty = {}
setmetatable(matrix, {__index=function() return empty end})
If I would like to allow writes and it's specifically two levels of tables, I could do:
setmetatable(matrix, {__index=function(t,k) local new={} rawset(t,k,new) return new end}
Hope this helps!