How can I use map in this kind of situation in grails? - loops

I need to display server info that are running up on ec2. I have managed to display them as a json, but now i only need to display certain fields. The following shows how I am displaying the statusCode and RunType. Similar concept is applied for other fields.
def check = reservations.each { Reservation reservation ->
reservation.instances.each() { Instance instance ->
def code = instance.state
def StatusCode = code.code
//Get other values
instance.tags.each() { Tag tag5 ->
def KeyName2 = tag5.key;
if (KeyName2 == 'RunType') {
def RunType = tag5.value;
}
}
}
instance.tags.each() { Tag tag2 ->
def KeyName2 = tag2.key;
if (KeyName2 == 'RunType') {
def value2 = tag2.value; }
}
instance.tags.each() { Tag tag3 ->
def KeyName3 = tag3.key;
if (KeyName3 == 'StartedBy') {
def value = tag3.value;
}
}
I wanna obtain something like this to display in my gsp page and loop it for every server.
def map = [StatusCode:"80", RunType:"Always", value"test", value2:"abc"]
But not sure on how to add values to the map when i obtain them thru the code

You might be able to use this:
def result = reservations.collectMany { reservation ->
reservation.instances.collect { instance ->
[ StatusCode: instance.code,
RunType : instance.tags.find { it.key == 'RunType' }?.value,
StartedBy : instance.tags.find { it.key == 'StartedBy' }?.value ]
}
}
Updated after the update to the question

From the code it looks like, a statusCode can have multiple value5. If that is not the case then you can do something like :
def myList = []
def check = reservations.each { Reservation reservation ->
reservation.instances.each() { Instance instance ->
def statusCode = instance.state?.code
def value5 = instance.tags?.find{it.key == 'RunType'}?.value
myList << ["StatusCode": statusCode, "RunType": value5 ]
}
}
Note the inner loop is simplified. I am not sure whether it meets your use case scenario since there are inner loops. If you think the map needs to be moved one level down inside the loop then you maintain a list of the key-value pairs (or the map) in the list as well.
The logic can be over-simplified using groovy's collect and inject functionality.

Related

Search array for a value [swift]

Just started learning swift, spent a few hours trying to figure this out by searching here but no luck so far.
I have an array, created like this:
class ProbabilitiesClass {
var list = [Odds]()
init() {
list.append(Odds(dateInit: -35, oddsTodayInit: "0,01", sevenDaysInit: "0,2"))
list.append(Odds(dateInit: -34, oddsTodayInit: "0,01", sevenDaysInit: "0,3"))
list.append(Odds(dateInit: -33, oddsTodayInit: "0,02", sevenDaysInit: "0,4"))
I want to search first parameter of this array for an integer and return its index.
Tried this
if let i = Odds.firstIndex(where: { $0.hasPrefix(differenceInDays) }) {
print("index is \([i])")
}
It returns error:
Type 'Odds' has no member 'firstIndex'
The end goal is to return second and third parameters of that index.
Update: I defined Odds like this:
import Foundation
class Odds {
let dateText : Int
let oddsToday : String
let odds7Days : String
init(dateInit: Int, oddsTodayInit: String, sevenDaysInit : String) {
dateText = dateInit
oddsToday = oddsTodayInit
odds7Days = sevenDaysInit
}
}
You could do it like so:
let p = ProbabilitiesClass()
let differenceInDays = -34
if let i = p.list.firstIndex(where: { $0.dateText == differenceInDays }) {
print("index is \([i])") //index is [1]
}
Look for the index in the list property of an instance of ProbabilitiesClass. And like the error message says: The class Odds is not an array to use the method firstIndex(where:) on it.
If you want to use the properties of the first element which has its dateInit equal to differenceInDays, then you could do it like so:
if let first = p.list.first(where: { $0.dateText == differenceInDays }) {
print("oddsTodayInit =", first.oddsToday)
print("sevenDaysInit =", first.odds7Days)
}
It uses this function first(where:).

Filter nested arrays with objects

I have an array of Categories. Each Category instance has offers property.
class Category {
var offers : [Offer]?
var title : String?
var id : Int?
}
class Offer {
var type : String?
}
//global variable
var categories = [ categ1, categ2, ...]
How can I filter categories by offer.type ?
I already have tried:
return categories.map { (category) -> Category in
let offers = category.offers?.filter { $0.type == myType }
category.offers = offers
return category
}
It works but after calling function second time array becomes empty. Probably because offers were rewritten?
Then I have tried this (produced same wrong result):
var resultCategories = [Category]()
for category in categories {
guard let offers = category.offers else { continue }
var newOffers = [Offer]()
for offer in offers {
if offer.type == myType {
newOffers.append(offer)
}
}
category.offers = newOffers
resultCategories.append(category)
}
return resultCategories
You should simply filter all categories that have no offers equals to your type. You can achieve that by:
filter all your categories and
inside the filter check if current offers contains the myType
Code:
let filtered = categories.filter { category in
category.offers?.contains(where: { $0.type == myType }) ?? false
}
And note, that category.offers?.[...] is optional value, so the ?? false returns false as result if left part is nil.
UPD.
But I expected that categories will have only offers with type = "A". Maybe I did not described the question accurately.
You can achieve that by creating a new Category.
let filtered = categories.compactMap { category -> Category? in
guard let offers = category.offers?.filter({ $0.type == "A" }) else { return nil }
let other = Category()
other.offers = offers
return other
}
Also note, i'm using compactMap. It allows me to filter categories with empty or nil offers out.
You can use simple and easy filter(functional programming) instead of for-loop.
First filter category then check offers contains particular type or not(using equal to condition)
let data = categories.filter { ($0.offers?.contains(where: {$0.type == "yourtype"})) ?? false
}
If you want multiple filter, like one field from one model and second field from nested array, please che
let searchText = "a"
let filteredCategoryList = list.filter { category in
let categoryFilter = category.title?.range(of: searchText, options: .caseInsensitive) != nil
let offerFilter = category.offers?.contains(where: { $0.type?.range(of: searchText, options: .caseInsensitive) != nil
})
return categoryFilter || offerFilter ?? false
}

Modify an array element after finding it in swift does not work

I wrote a model like this as an exercise :
struct Store {
var name : String
var bills : Array<Bill>
var category : Category?
}
struct Bill {
var date : String
var amount : Float
}
struct Category {
var name : String
var tags : Array<String>
}
and when I'm searching if a store already exist to add a bill to it instead of creating a new store, my code doesn't work. It acts like if the result of the search is a copy of the Array element . I would like to have a reference.
var stores : Array <Store> = Array()
for billStatment in billStatements! {
let billParts = billStatment.split(separator: ",")
if billParts.count > 0 {
let bill : Bill = Bill(date:String(billParts[0]), amount: Float(billParts[2])!)
var store : Store = Store(name:String(billParts[1]), bills: [bill], category: nil)
if var alreadyAddedStore = stores.first(where: {$0.name == String(billParts[1])}) {
alreadyAddedStore.bills.append(bill)
print("yeah found it \(alreadyAddedStore)") // the debugger breaks here so I know the "first" method is working. If I print alreadyAddedStore here I have one more element, that's fine.
} else {
stores.append(store)
}
}
}
print("\(stores.count)") // If I break here for a given store that should contains multiple elements, I will see only the first one added in the else statement.
Can anyone tell me what I am doing wrong?
As already noted, you're confusing value (struct) semantics with reference (class) semantics.
One simple fix would be the change stores to a dictionary with the name as your key:
var stores : Dictionary<String, Store> = [:]
and use it like this:
if(stores[store.name] == nil) {
stores[store.name] = store
}
else {
stores[storeName].bills.append(bill)
}

Scala returning multi-dimensional arrays

I am trying to make a simple minesweeper game in Scala and I am trying to make a method that calls a nested method for randomly placing mines into the grid.
I am using the ofDim method on the Array to make it multi-dimensional which works great, until I specify it as the methods return type. The error I get is:
type ofDim is not a member of Object Array
The code is as follows:
class GridBuilder(x:Int, y:Int, mines:Int) {
def generateGrid: Array.ofDim[String](x, y) = {
def placeMines(mineLocations: Array.ofDim[String](x, y)): Array.ofDim[String](x, y) = {
val xcoord = Random.nextInt(x)
val ycoord = Random.nextInt(y)
if (mineLocations.count(_ == "Bomb") == mines)
mineLocations
else if (mineLocations(xcoord) (ycoord) contains "Mine")
placeMines(mineLocations)
else
placeMines(mineLocations(xcoord)(ycoord) = "Mine")
}
placeMines(new Array.ofDim[String](x, y))
}
}
I haven't found anything about returning multi-dimensional arrays anywhere. Is this possible in Scala? What am I missing here?
Array.ofDim is a method, not a type,
If you look at how it's implemented, it's a bunch of overloaded methods, each having different return type. In your case Array[Array[String]].
I threw together a quick little example so you can compare what you end up with. It is by no means perfect, and doesn't cover invalid user input, or game over etc, but here it is anyway.
import scala.annotation.tailrec
import scala.util.Random
sealed trait GridValue
case object Bomb extends GridValue
case object Empty extends GridValue
case object Checked extends GridValue
case class Grid(private var grid: List[List[GridValue]]){
def click(x: Int, y: Int): String = {
grid(x)(y) match {
case Bomb => "BOOM! You lose!"
case Empty =>
grid = grid.updated(x, grid(x).updated(y, Checked))
"No bomb! Good Job"
case Checked => "You've already clicked here!"
}
}
}
object Grid{
def buildGrid(x: Int, y: Int, mines: Int): Grid = {
#tailrec
def placeMines(grid: List[List[GridValue]] = List.fill(x)(List.fill(y)(Empty)), minesRemaining: Int = mines): List[List[GridValue]] = {
if(minesRemaining == 0) {
grid
} else {
val xcoord = Random.nextInt(x)
val ycoord = Random.nextInt(y)
grid(xcoord)(ycoord) match {
case Bomb => placeMines(grid, minesRemaining)
case Empty => placeMines(grid.updated(xcoord,grid(xcoord).updated(ycoord, Bomb)), minesRemaining - 1)
}
}
}
Grid(placeMines())
}
}
//Start game: val game = Grid.buildGrid(100, 100, 5)
//Click: game.click(10, 10)

Groovy ConfigSlurper Configure Arrays

I am trying to create a config that would look something like this:
nods = [
nod {
test = 1
},
nod {
test = 2
}
]
and then use configSlurper to read it but the "node" objects appear to be null after the read.
Here is my code:
final ConfigObject data = new ConfigSlurper().parse(new File("config.dat").toURI().toURL())
println data.nods
and the output:
[null, null]
What am I doing wrong?
Thanks!
It think I resolved it this way:
config {
nods = [
['name':'nod1', 'test':true],
['name':'nod2', 'test':flase]
]
}
And then using it like:
config = new ConfigSlurper().parse(new File("config.groovy").text)
for( i in 0..config.config.nods.size()-1)
println config.config.nods[i].test
Hope this helps someone else!!
You have to be careful when using ConfigSlurper when doing this sort of thing.
For example your solution will actually produce the following output:
true
[:]
If you look carefully you will notice that there is a typo on the second array value flase instead of false
The following:
def configObj = new ConfigSlurper().parse("config { nods=[[test:true],[test:false]] }")
configObj.config.nods.each { println it.test }
should produce the correct result:
true
false
I tried to parse with ConfigSlurper something like this:
config {sha=[{from = 123;to = 234},{from = 234;to = 567}]}
The array "sha" was far from what expected.
To get "sha" as an array of ConfigObjects I used a helper:
class ClosureScript extends Script {
Closure closure
def run() {
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure.delegate = this
closure.call()
}
}
def item(closure) {
def eng = new ConfigSlurper()
def script = new ClosureScript(closure: closure)
eng.parse(script)
}
this way I get an array of ConfigObjects:
void testSha() {
def config = {sha=[item {from = 123;to = 234}, item {from = 234;to = 567}]}
def xx = item(config)
assertEquals(123, xx.sha[0].from)
}

Resources