converting set to a map groovy - grails

I have my logic in my postprocess to process the values of devices and files as below :(changed this to set from map as it was overriding the values)
def deviceFiles = devices.inject([] as Set) { deviceFiles, device ->
def v = device.key.split( /\./ )[0]
deviceFiles << [ (device.value), files[ v ] ]
}
output : deviceFiles :[[Acer C6, Tetris.apk], [Motorola Droid Milestone, Tetris.apk], [Acer C6, TheSims3.apk], [HTC Desire, TheSims3.apk]] --- looks good to be displayed
These values are to be passed as a map/properties so that the data would be displayed properly without any cast exceptions, which I am finding tough..
when it is looped through the set
deviceFiles.each { device ->
mapping.put("${device}", "${file}")
}
output : mapping :[HTC Desire:TheSims3.apk, Motorola Droid Milestone:Tetris.apk, Acer C6:Tetris.apk] -- which is not correct (Acer C6:TheSims3.apk has been overriden)
Am I missing something here in sending the expected values into map? or it is not possible to send the values of set through map(as map always eliminates the duplicates when i am iterating through devices) ???

You could use collectEntries:
def deviceFiles = devices.collectEntries {
device -> [device.value, device.key.split(/\./)[0]]
}

You can use groupBy for this. Assuming your set consists of:
def deviceFiles = [["Acer", "test.apk"], ["Acer", "abc.apk"], ["HTC", "qwer.apk"]]
def mapping = deviceFiles.groupBy { it[0] }
Will result in:
["Acer": [["Acer", "test.apk"], ["Acer", "abc.apk"]], "HTC": [["HTC", "qwer.apk"]]]

Related

Re-initialize table without losing references

I'd like to re-initialize a table without losing references to it.
What I want to achieve is defining tables in files, and when a file is changed (with a text editor) the file is reloaded, changing the table. Of course this doesn't change the table but creates a new instance, old references will still point to the old table.
Any suggestions?
EDIT: I want to elaborate on what I want to achieve. An example with game characters and weapons. I want to modify the weapons.lua and so affect the characters.
-- weapons.lua
sword = { damage = 3 }
-- characters.lua
character = { weapon = sword }
Adding a level of indirection (putting "sword" inside "weapons") like suggested by JWT doesn't help, unless I split character into { weaponTable = weapons, weaponKey = "sword" } but I don't see this as an option.
Anchor everything that needs to survive in the global environment. Nesting is fine, and this doesn't have to be your primary reference. (You can still local things, but make sure to initialize those local variables from the global environment and update the global if you change the local.)
To initialize the global values, say
foo = foo or value -- if foo is always true-ish
bar = (bar == nil) and value or bar -- if bar may be `false`
To initialize or update tables, you can
foo = foo or { }
foo.bar = foo.bar or 23
foo.baz = foo.baz or 42
-- and so on...
but that's kinda icky, so maybe say
function reinit( new, old ) -- (re)initialize one level, prefer old
if old == nil then return new end
if type( old ) ~= "table" then return old end
for k, v in pairs( new ) do
if old[k] == nil then old[k] = v end
end
return old
end
function reset( new, old ) -- (re)initialize one level, prefer new
if old == nil then return new end
if type( old ) ~= "table" then return new end
for k, v in pairs( new ) do old[k] = v end
return old
end
and then just
foo = reinit( { bar = 23, baz = 42 }, foo ) -- only setting if not defined
-- or
foo = reset( { bar = 23, baz = 42 }, foo ) -- always overriding given fields
or maybe make it even more fancy and say
function traverse( t, path )
local here, last, lastk, created = t
-- follow path of several keys starting from t, creating tables as needed
for k in path:gmatch "[^.]+" do
k = tonumber( k ) or k -- convert all-number keys to integer (for arrays)
local next = here[k]
if not next then
next, created = { }, true
here[k] = next
else
created = false
end
lastk, last, here = k, here, next
end
return here, last, lastk, created
end
function repopulate( path, value, update )
update = update or reinit -- pass 'reset' as 'update' for the other behavior
-- or something entirely different if that's what you need
local here, last, lastk, created = traverse( _G, path )
if type( value ) == "table" then
update( value, here )
else
if created then last[lastk] = nil end -- created one level too much
update( { [lastk] = value }, last )
end
end
and then (with arbitrary nesting)
-- No need to create 'state' first if it doesn't exist yet!
-- (If it exists, it will get updated, otherwise it's created)
repopulate( "state.player.weapon", { kind = "sword", damage = 11 } )
-- Do keep in mind that generally update order is relevant -- you may want to
-- give a newly created player a default inventory, but you may not want to
-- "refill" the player's inventory on every reload. So generally `repopulate`
-- with the parent and all child nodes for from-scratch creation, then
-- `repopulate` the child nodes that need to be checked & potentially updated
-- as well.
-- (So here you'd probably repopulate `state.player` first and then
-- `state.player.weapon` or other fields only if they should be updated anyway.)
-- e.g.:
repopulate( "state.player", {
x = 0, y = 0, hp = 100, mp = 100, level = 0, -- and so on
weapon = { kind = "sword", damage = 11 }, -- etc. etc.
} )
-- on reload always force a sword-kind weapon, leave rest (damage, ...) as-is
repopulate( "state.player.weapon", { kind = "sword" }, reset )
-- or alternatively: only if player has no weapon, give them a sword
repopulate( "state.player.weapon", { kind = "sword", damage = 3 } )
And you can go further, add metamethods to hide some of that shuffling, define different update policies, ... – you've seen some of the possibilities, now go and build your own version that fits your style and your code.
(While you're free to use the above code in any way, please note that it was written ad-hoc in the browser. I did some testing, fixed some glitches, and it seems to work now, but don't be surprised if there's still one or two bugs hiding in there. So play with this, change it, break it (and see how/why it breaks), adapt and extend it, ... – but unless you completely understand what it does and can fix any bugs, I strongly suggest you write your own version, or just stick to the basics. You probably don't need everything that this does, and you're likely to need other things that this doesn't do. As this is a central part of the reloading/live-coding infrastructure and everything has to be adapted to be reload-compatible, any mismatch between your tooling and what you actually need will result in a lot of pain everywhere in your code. So if you need something like this, put in a day or two to make it work the way you need it to, or you will regret it.)
(Free bonus warning: If you do OOP, you'll probably have to store and retrieve your classes instead of creating them every time, otherwise old objects from previous iterations will miss code updates and still run their old methods. I've forgotten about that more than just a couple of times and wasted several hours pondering "why isn't it fixed now?!?" after repeatedly re-loading code... So remember to anchor your metatables, anchor your classes!)
You could nest the tables in another table.
Before:
local a = { 1, 2, 3 }
local b = { 7, 8, 9 }
print(a[2] + b[2]) -- #=> 10
After:
local lookup = {
a = { 1, 2, 3 },
b = { 7, 8, 9 }
}
print(lookup.a[2] + lookup.b[2]) -- #=> 10
Then you can fully replace (or just update) a table in the lookup table and any dependent statements will use that updated value:
lookup.a = { 100, 50, 0 }
print(lookup.a[2] + lookup.b[2]) -- #=> 58
I don't know if it's exactly what you needed (As an ID is necessary) but I hope it will fit your needs.
meta = {
tables = {},
__call = function(arg, t)
for k, v in pairs(t) do
arg[k] = v
end
end,
__bnot = function(arg)
return arg.__key
end,
__newindex = function(arg, key, val)
meta.tables[arg.__key][key] = val
end,
__index = function(arg, key)
return meta.tables[arg.__key][key]
end
}
function RefTable(arg)
local newtable = {}
if arg ~= nil then
newtable.__key = arg
setmetatable(newtable, meta)
if meta.tables[arg] == nil then
meta.tables[arg] = {}
end
else
error("RefTable can't have nil key")
end
return newtable
end
-- Using the RefTable
sword = RefTable("Sword")
sword({damage = 3})
sword.cooldown = 10
character = {sword = sword}
print("base", sword.damage, sword.cooldown)
print("embed", character.sword.damage, character.sword.cooldown)
sword = RefTable("Sword")
sword({damage = 8, cooldown = 50})
print("embed2", character.sword.damage, character.sword.cooldown)
print(sword.__key, sword.cooldown)
ref = RefTable("Sword")
ref.cooldown = 1000
print(sword.cooldown)

How to use patterns to shorten only matching strings

I have a program that grabs a list of peripheral types, matches them to see if they're a valid type, and then executes type-specific code if they are valid.
However, some of the types can share parts of their name, with the only difference being their tier, I want to match these to the base type listed in a table of valid peripherals, but I can't figure out how to use a pattern to match them without the pattern returning nil for everything that doesn't match.
Here is the code to demonstrate my problem:
connectedPeripherals = {
[1] = "tile_thermalexpansion_cell_basic_name",
[2] = "modem",
[3] = "BigReactors-Turbine",
[4] = "tile_thermalexpansion_cell_resonant_name",
[5] = "monitor",
[6] = "tile_thermalexpansion_cell_hardened_name",
[7] = "tile_thermalexpansion_cell_reinforced_name",
[8] = "tile_blockcapacitorbank_name"
}
validPeripherals = {
["tile_thermalexpansion_cell"]=true,
["tile_blockcapacitorbank_name"]=true,
["monitor"]=true,
["BigReactors-Turbine"]=true,
["BigReactors-Reactor"]=true
}
for i = 1, #connectedPeripherals do
local periFunctions = {
["tile_thermalexpansion_cell"] = function()
--content
end,
["tile_blockcapacitorbank_name"] = function()
--content
end,
["monitor"] = function()
--content
end,
["BigReactors-Turbine"] = function()
--content
end,
["BigReactors-Reactor"] = function()
--content
end
}
if validPeripherals[connectedPeripherals[i]] then periFunctions[connectedPeripherals[i]]() end
end
If I try to run it like that, all of the thermalexpansioncells aren't recognized as valid peripherals, and if I add a pattern matching statement, it works for the thermalexpansioncells, but returns nil for everything else and causes an exception.
How do I do a match statement that only returns a shortened string for things that match and returns the original string for things that don't?
Is this possible?
If the short version doesn't contain any of the special characters from Lua patterns you can use the following:
long = "tile_thermalexpansion_cell_basic_name"
result = long:match("tile_thermalexpansion_cell") or long
print(result) -- prints the shorter version
result = long:match("foo") or long
print(result) -- prints the long version
Based on the comment, you can also use string.find to see the types match your peripheral names:
for i,v in ipairs(connectedPeripherals) do
local Valid = CheckValidity(v)
if Valid then Valid() end
end
where, CheckValidity will return the key from validPeripherals:
function CheckValidity( name )
for n, b in pairs(validPeripherals) do
if name:find( n ) then return n end
end
return false
end

Accessing config variables stored in maps by key

I have a variable in groovy like below:
project.Map
{
time.'1 1 * ?' = ['T1']
time.'2 1 * ?' = ['T2']
templates.'T1' = ['Z','X','Y']
templates.'T2' = ['Q']
}
Sorry but I am new to groovy ,when i try to access the individual
variable values in project.map how do i access them
i tried something like below
log.info(grailsApplication.config.project.Map.time[1])
log.info(grailsApplication.config.project.Map.get('time.'2 1 * ?'' ))
log.info(grailsApplication.config.project.Map.get('time[0]' ))
log.info(grailsApplication.config.project.Map.time.get('1 1 * ?'))
but they all print null value or object references.how do i access values for
time and templates both within a for loop and without it.
please see http://grails.org/doc/latest/guide/conf.html#config for the ways the config is allowed to nest. your outer syntax is especially mentioned to not be allowed:
However, you can't nest after using the dot notation. In other words, this won't work:
// Won't work!
foo.bar {
hello = "world"
good = "bye"
}
You have to write it as
project { Map { ... } }
The inner dotted parts (with the assignment) are ok (according to the doc)

What is the best way in ruby to find if all the elements of one array are also present or not in the other array

I have following two arrays
a= [1,2,3,4]
b= [1,2]
c= [1,2,3,4,5]
I want a method which return boolean value something like following
a.<some_method>(b) #should return true
b.<some_method>(c) #should return false
suppose i use include? it will not work as it is expecting b as an element in the other array
currently i am doing something like following
b.all?{|x| a.include?(x) }
I want to know is there any better/fast way as my both the arrays having large lengths
Just check the result of second array subtracted from first array.
In your case B - A will be empty, but C - A will be non-empty...
In the simplest case the array operations are good.
But for extensive cases I think you need set operations. You can have a look at http://www.ruby-doc.org/stdlib-1.9.3/libdoc/set/rdoc/Set.html.
Like in your case, it should be
a= [1,2,3,4].to_set
b= [1,2].to_set
c= [1,2,3,4,5].to_set
a.superset?(b) # -> true
b.superset?(c) # -> false
array & other_array returns the matching elements between array and other array and removes any duplicates. You can create a boolean test to see if all elements of one array are in another by comparing the unique elements of the one array to the intersecting elements of the two combined arrays.
a = [1,2,3,4,5]
b = [2,3,4,5]
c = [4,5,6,7]
# check if all items in one array are in another array
def all_items_in_array?(original_array, test_array)
test_array.uniq == original_array & test_array
end
This method will return a boolean value
all_items_in_array?(a,b) # true
all_items_in_array?(a,c) # false
all_items_in_array?(b,c) # false
and for a boolean check with dupilcations
def all_items_including_duplicates_in_array?(original_array, test_array)
original_grouped = original_array.group_by{|item| item}.values
test_grouped = test_array.group_by{|item| item}.values
test_grouped == original_grouped & test_grouped
end
Both the array difference and Set#subset? answers are nice, but OP asked specifically about speed. The best way to answer performance questions is to actually time the different approaches. Benchmark to the rescue:
require 'benchmark'
require 'set'
BIG = 10_000
N = 1_000_000
SLOW_N = 500
a = [1,2,3,4]
b = [1,2]
c = [1,2,3,4,5]
bigA = (1..BIG).to_a
bigB = bigA.dup
bigB.pop
bigC = bigA.dup << (BIG+1)
setA = a.to_set
setB = b.to_set
setC = c.to_set
bigsetA = bigA.to_set
bigsetB = bigB.to_set
bigsetC = bigC.to_set
puts RUBY_DESCRIPTION
Benchmark.bm(21) do |x|
x.report('Array#-') { N.times{ (b-a).empty?; (c-a).empty? } }
x.report('Set#subset?') { N.times{ setB.subset?(setA); setC.subset?(setA) } }
x.report('big Array#-') { SLOW_N.times{ (bigB-bigA).empty?; (bigC-bigA).empty? } }
x.report('big Set#subset?') { SLOW_N.times{ bigsetB.subset?(bigsetA); bigsetC.subset?(bigsetA) } }
x.report('big all? Set#include?') { SLOW_N.times{ bigB.all?{|x| bigsetA.include?(x)}; bigC.all?{|x| bigsetA.include?(x)} } }
end
Results show that for small sets there's no significant difference. For large ones Set#subset? is about 20% faster:
ruby 1.9.3p125 (2012-02-16 revision 34643) [x86_64-linux]
user system total real
Array#- 1.520000 0.000000 1.520000 ( 1.518501)
Set#subset? 1.520000 0.000000 1.520000 ( 1.533306)
big Array#- 2.180000 0.000000 2.180000 ( 2.180390)
big Set#subset? 1.720000 0.000000 1.720000 ( 1.724991)
big all? Set#include? 2.130000 0.000000 2.130000 ( 2.142015)
arr = [a, b, c]
arr.reduce(:&)
will get you the consistent elements
I am after the inconsistent ones as well.
You can also do this:
a = [1,2,3]
b = [2,4,6]
c = [2,3,4]
(a & b).any? or (a & b & c).any?

many to many mapping in Grails

devices :[1.1:Acer C6, 2:Acer C6, 1:Acer C6, 2.2:HTC Magic]
files :[2:Tetris.apk, 1:TheSims3.apk]
I have a mapping of files and devies, as of now its one-to-many mapping.
devices :[1.1:Acer C6, 2:Acer C6, 1:Acer C6, 2.2:HTC Magic]
files :[2:Tetris.apk, 1:TheSims3.apk]
Now I need to implement many-to-many mapping
my logic for one-to-many mapping is
mapping = params.devices.inject( [:] ) { map, dev ->
// Get the first part of the version (up to the first dot)
def v = dev.key.split( /\./ )[ 0 ]
logger.debug("value of v :"+v)
map << [ (dev.value): files[ v ] ]
}
current output is - mapping :[Acer C6:Tetris.apk, HTC Magic:Tetris.apk]
expected output : [Acer C6:Tetris.apk, Acer C6:TheSims3.apk, HTC Magic:Tetris.apk]
You are accumulating your results using the device name as a key. When a new value is added to the map, it overwrites the last one with the same key.
You could try accumulating into a Set instead of a map. Example:
def devices = ['1.1': 'Acer C6', '2': 'Acer C6', '1': 'Acer C6', '2.2': 'HTC Magic']
def files = ['2': 'Tetris.apk', '1': 'TheSims3.apk']
def deviceFiles = devices.inject([] as Set) { deviceFiles, device ->
def v = device.key.split( /\./ )[0]
deviceFiles << [ (device.value), files[ v ] ]
}
assert deviceFiles == [
['Acer C6', 'Tetris.apk'],
['Acer C6', 'TheSims3.apk'],
['HTC Magic', 'Tetris.apk']
] as Set

Resources