Is there a way to find an element in a list and delete items after it that are of a specific type without using indicies? - list

I have a project that needs me to remove items if one of the properties of the item I'm trying to find within the list is true. Just so it's easier understand the project I am pasting all code needed to understand it below.
fun main() {
val acct1 = AccountId(72)
val calendars = mutableListOf<CalendarDrawerCalendarItem>()
val calendars2 = mutableListOf<CalendarDrawerCalendarItem>()
calendars.add(CalendarDrawerCalendarItem(CalendarDescriptor(acct1, CalendarId(acct1, 3),"toast", true)))
calendars.add(CalendarDrawerCalendarItem(CalendarDescriptor(acct1, CalendarId(acct1, 4), "chicken", false)))
calendars.add(CalendarDrawerCalendarItem(CalendarDescriptor(acct1, CalendarId(acct1, 5), "pizza", true)))
calendars2.add(CalendarDrawerCalendarItem(CalendarDescriptor(acct1, CalendarId(acct1, 1), "bagel", true)))
// These are example calls to collapse
collapse(calendars, CalendarDrawerGroupItem(true, CalendarGroupDescriptor( acct1, "My Calendars")))
collapse(calendars2, CalendarDrawerGroupItem(false, CalendarGroupDescriptor(acct1, "Group Calendars")))
}
fun collapse(calendars: List<CalendarDrawerListItem>, group: CalendarDrawerGroupItem): List<CalendarDrawerListItem> {
val collapsedResults = mutableListOf<CalendarDrawerListItem>()
val findGroupGiven = group
collapsedResults.addAll(calendars)
if (collapsedResults.contains(findGroupGiven)) {
group.collapsed = true
// logic for deleting items here
}
return collapsedResults
}
I'll also put the classes so you can see how they're defined
data class AccountId(
val accountId: Int
)
data class CalendarId(
val accountId: AccountId,
val calendarId: Int)
data class CalendarDescriptor(
val accountId: AccountId,
val calendarId: CalendarId,
val name: String,
val isGroupCalendar: Boolean
)
data class CalendarGroupDescriptor(
val accountId: AccountId,
val name: String,
)
sealed class CalendarDrawerListItem
data class CalendarDrawerGroupItem(var collapsed: Boolean, val groupDescriptor: CalendarGroupDescriptor) : CalendarDrawerListItem()
data class CalendarDrawerCalendarItem(val calendarDescriptor: CalendarDescriptor) : CalendarDrawerListItem()
The first step I have done is I must find the given group from the group variable, within calendars. (I did this with the contains() method). Next when I find the group I have to set its collapsed variable to true and any CalendarDrawerCalendarItems after it have to be deleted.
The input will look something like (the exact numbers and values are not the important part):
Input:
calendars:
CDGroupItem(collapsed = false, groupDescriptor = GroupDescriptor(accountId = 1, name = "My calendars"))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 1, isGroup = false))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 2, isGroup = false))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 3, isGroup = false))
CDGroupItem(collapsed = false, groupDescriptor = GroupDescriptor(accountId = 1, name = "Group calendars"))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 4, isGroup = true))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 5, isGroup = true))
group: CDGroupItem(collapsed = false, groupDescriptor = GroupDescriptor(accountId = 1, name = "My calendars"))
The output should look something like this:
Output:
CDGroupItem(collapsed = true, groupDescriptor = GroupDescriptor(accountId = 1, name = "My calendars"))
CDGroupItem(collapsed = false, groupDescriptor = GroupDescriptor(accountId = 1, name = "Group calendars"))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 4, isGroup = true))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 5, isGroup = true))
Any group item that has its collapsed boolean set to true should have all calendar items deleted after it since its collapsed is set to true. Again the names and numbers are not super important. The collapsed bool is. How can I do this without hardcoding or using indicies?

Your example code doesn't use that input and output as-is so I can only give you a general example, but you could use a fold:
val result = calendars.fold(mutableListOf<CalendarDrawerListItem>()) { items, current ->
// basically 'is there a last item stored, and is it a group item, and is it collapsed'
val lastStoredIsCollapsed =
(items.lastOrNull() as? CalendarDrawerGroupItem)?.collapsed == true
if (current is CalendarDrawerCalendarItem && lastStoredIsCollapsed) items
else items.apply { add(current) }
}
It basically pipes out each item into a list, but if the last one it stored is a CalendarDrawerGroupItem with collapsed set to true, it drops drawer items. If the last one is a non-collapsed group item, it can store a drawer item, and that means the next drawer item will be stored (since the last item isn't a collapsed group)
edit: here's the for loop equivalent if it helps, with the full logic for when a calendar is not dropped (the logic in my other example is for whether it should be dropped, which can be condensed a bit):
// assuming 'calendars' is your list of items with 'collapsed' set appropriately
val result = mutableListOf<CalendarDrawerListItem)
for (calendar in calendars) {
val lastStored = result.lastOrNull()
when {
lastStored == null ->
result.add(calendar)
lastStored is CalendarDrawerGroupItem && !lastStored.collapsed ->
result.add(calendar)
lastStored is CalendarDrawerCalendarItem ->
result.add(calendar)
}
}
return result
If you're asking how to actually mutate your list so a collapsed property is set to true, that would be easy if the property was a var in your data class. Since it's a val you'll have to do something like this:
val calendarInputWithCollapsedSet = calendars.map { calendar ->
if ((calendar as? CalendarDrawerGroupItem)?.groupDescriptor == group.groupDescriptor)
calendar.copy(collapsed = true) else calendar
}
So if you find a matching group (you'll have to work out how to match them, I'm guessing) you transform it into a copy with its collapsed property set
And then you can run the fold or whatever on that new list.

Related

Terraform aws_cloudfront_cache_policy pass multiple cookies to cookies_config

I can't seem to pass multiple cookies in the "items" list when in "cookies_config -> cookies"
Here is my variable:
variable "cache_policy_defaults" {
type = object({
name = string
comment = string
default_ttl = number
max_ttl = number
min_ttl = number
cookie_behavior = string
cookies_to_forward = optional(list(string))
header_behavior = string
headers_to_forward = optional(list(string))
query_string_behavior = string
query_strings_to_forward = optional(list(string))
}
)
default = {
name = ""
comment = ""
default_ttl = 60
max_ttl = 60
min_ttl = 60
cookie_behavior = "none"
cookies_to_forward = []
header_behavior = "none"
headers_to_forward = []
query_string_behavior = "none"
query_strings_to_forward = []
}
}
Here are my locals:
locals {
origin_id = "origin_${local.origin_config.domain_name}"
origin_config = merge(var.origin_defaults, var.origin_settings)
restrictions = merge(var.restrictions_defaults, var.restrictions_settings)
default_cache_behavior = merge(var.default_cache_behavior_defaults, var.default_cache_behavior_settings)
cache_policy = merge(var.cache_policy_defaults, var.cache_policy_settings)
cache_policy_name = "cache_policy_${var.name}"
}
Here is my tfvars:
"cache_policy_settings": {
"min_ttl": 30,
"max_ttl": 30,
"default_ttl": 30,
"cookie_behavior": "whitelist",
"cookies_to_forward": ["123", "456"]
}
Here is my main.tf:
resource "aws_cloudfront_cache_policy" "this" {
name = lookup(local.cache_policy, local.cache_policy.name, local.cache_policy_name)
comment = local.cache_policy.comment
default_ttl = local.cache_policy.default_ttl
max_ttl = local.cache_policy.max_ttl
min_ttl = local.cache_policy.min_ttl
parameters_in_cache_key_and_forwarded_to_origin {
cookies_config {
cookie_behavior = local.cache_policy.cookie_behavior
dynamic "cookies" {
for_each = local.cache_policy.cookies_to_forward != null ? local.cache_policy.cookies_to_forward : null
content {
items = local.cache_policy.cookies_to_forward
}
}
}
headers_config {
header_behavior = local.cache_policy.header_behavior
dynamic "headers" {
for_each = local.cache_policy.headers_to_forward != null ? local.cache_policy.headers_to_forward : null
content {
items = local.cache_policy.headers_to_forward
}
}
}
query_strings_config {
query_string_behavior = local.cache_policy.query_string_behavior
dynamic "query_strings" {
for_each = local.cache_policy.query_strings_to_forward != null ? local.cache_policy.query_strings_to_forward : null
content {
items = local.cache_policy.query_strings_to_forward
}
}
}
}
}
The docs state
items: (Required) A list of item names (cookies, headers, or query strings).
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_cache_policy#items
However, the list does not accept multiple items.
Error: Too many list items
on main.tf line 57, in resource "aws_cloudfront_cache_policy" "this":
57: cookies_config {
Attribute supports 1 item maximum, but config has 2 declared.
It seems that I should just be able to pass a list of items? If I change the my input list to only contain a single value, then it works.
Here is the trick:
for_each = local.cache_policy.cookies_to_forward != null ? [1] : null
This tells Terraform to create exactly one block by making the true value of the ternary [1].
Thanks Jason for putting me on the right track.

Kotlin How to integrate/merge with same value in the List of data class

I want to merge same "startime" to one (step, distance and calorie) in the list, how can I to do this.
var listNewStepData = arrayListOf<NewStepData>()
data class
data class NewStepData (
val startTime: String?,
val endTime: String?,
val step: Int? = 0,
val distance: Int? = 0,
val calorie: Int? = 0
)
this is sample
NewStepData(startTime=2020-04-14T00:00:00.000Z, endTime=2020-04-14T00:00:00.000Z, step=4433, distance=0, calorie=0)
NewStepData(startTime=2020-04-14T00:00:00.000Z, endTime=2020-04-15T00:00:00.000Z, step=0, distance=0, calorie=1697)
NewStepData(startTime=2020-04-14T00:00:00.000Z, endTime=2020-04-14T00:00:00.000Z, step=0, distance=2436, calorie=0)
NewStepData(startTime=2020-04-15T00:00:00.000Z, endTime=2020-04-15T00:00:00.000Z, step=5423, distance=0, calorie=0)
NewStepData(startTime=2020-04-15T00:00:00.000Z, endTime=2020-04-16T00:00:00.000Z, step=0, distance=0, calorie=1715)
NewStepData(startTime=2020-04-15T00:00:00.000Z, endTime=2020-04-15T00:00:00.000Z, step=0, distance=3196, calorie=0)
I want to get this
NewStepData(startTime=2020-04-14T00:00:00.000Z, endTime=2020-04-15T00:00:00.000Z, step=4433, distance=2436, calorie=1697)
NewStepData(startTime=2020-04-15T00:00:00.000Z, endTime=2020-04-16T00:00:00.000Z, step=5423, distance=3196, calorie=1715)
thanks
You can use groupBy { } for your list. It will return a map of your grouping variable type to lists of your original type. And then, use flatMap to aggregate your data.
I assume that you take maximum end date which is maxBy and sum of distances, and steps which you need sumBy for, and calories which sumByDouble is the best choice.
Here's the sample code:
var grouped = listNewStepData.groupBy { it.startTime }.flatMap { entry -> NewStepData(startTime = entry.key,
endTime = entry.value.maxBy { item -> item.endTime },
step = entry.value.sumBy { item -> item.step },
distance = entry.value.sumBy { item -> item.distance },
calorie = entry.value.sumByDouble { item -> item.calorie })
}

how can i execute or not a line of a for-comprehension depending on a condition, with scala slickdb

I have this code using slickdb:
val action: DBIOAction[Int, NoStream, Effect] =
for {
id <- sql"select id from product where name = $name".as[Int].head
_ <- sql"update product set description = ${description(id, name)}".asUpdate if id != 5
} yield id
db.run(action)
With this code, the action will not return the id if id != 5. This is not what I want. I want that the set description update is only executed if id != 5, and at the same time dbaction must return the id independenting or whether id != 5 or not.
How can I achieve this?
You might need something like this:
val action: DBIOAction[Int, NoStream, Effect] =
for {
id <- sql"select id from product where name = $name".as[Int].head
} yield {
if (id != 5) {sql"update product set description = ${description(id, name)}".asUpdate }
id
}

How to do a MaxBy in RavenDb MapReduce

Using the Northwind database from RavenDB tutorial I'm trying to group orders by employee and get the most resent order for every employee.
Map:
from order in docs.Orders
select new {
Employee = order.Employee,
Count = 1,
MostRecent = order.OrderedAt,
MostRecentOrderId = order.Id
}
Reduce with nonexisting MaxBy:
from result in results
group result by result.Employee into grp
select new {
Employee = grp.Key,
Count = grp.Sum(result => result.Count),
MostRecent = grp.Max(result => result.MostRecent),
MostRecentOrderId = grp.MaxBy(result => result.MostRecent).MostRecentOrderId,
}
Reduce attempt:
from result in results
group result by result.Employee into grp
let TempMostRecent = grp.Max(result => result.MostRecent)
select new {
Employee = grp.Key,
Count = grp.Sum(result => result.Count),
MostRecent = TempMostRecent,
MostRecentOrderId = grp.First(result => result.MostRecent == TempMostRecent).MostRecentOrderId
}
However my reduce attempt returns 0 results.
Also: will RavenDB treat the Order.OrderetAt as a proper DateTime value and order them correctly?
You need to do it like
from order in docs.Orders
select new {
Employee = order.Employee,
Count = 1,
MostRecent = order.OrderedAt,
MostRecentOrderId = order.Id
}
from result in results
group result by result.Employee into grp
let maxOrder = grp.OrderByDescending(x=>x.MostRecent).First()
select new {
Employee = grp.Key,
Count = grp.Sum(result => result.Count),
MostRecent = maxOrder.MostRecent,
MostRecentOrderId = maxOrder.MostRecentOrderId,
}

Text giving constantly feedback about current selection

I am writing a script which has an UI in Maya. I have a text box that is supposed to constantly update based on the last item in the users selection list. How would I go about something that constantly keeps checken whithout having the user to push a button or something manually to call a function.
Thx
Edit: Cool that is what I was looking for. Thx. Your script works just fine. I tried implementing that into my big script which resulted in that every button in the UI had to be pushed twice in order to take effect. But I will deal with that later. However testing my own version in a seperate script as follows sometimes produces the following error: 'sl' must be passed a boolean argument
#________________________________________________________________________________________________________________________________________________
import maya.cmds as cmds
idManagerUI = cmds.window(title='Vray ID Manager', s = False, wh = (305,500))
cmds.columnLayout(adj = True)
cmds.text (l = '__________________________________________ \n your current selection has this ID: \n')
curSelTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])
def update_label(*_):
upCurrentObjectSel = cmds.ls(sl=True)
upCurrentObjectSelShapes = cmds.listRelatives(upCurrentObjectSel)
upLastobj = upCurrentObjectSelShapes[-1]
print upLastobj
cmds.text(curSelTxt, e=True, label = upLastobj)
cmds.scriptJob(event=("SelectionChanged", update_label), p= curSelTxt)
cmds.showWindow(idManagerUI)
Also, making two of these ScriptJobs makes the script stop working properly entirely.
#________________________________________________________________________________________________________________________________________________
import maya.cmds as cmds
idManagerUI = cmds.window(title='Vray ID Manager', s = False, wh = (305,500))
cmds.columnLayout(adj = True)
cmds.text (l = '__________________________________________ \n your current selection has this ID: \n')
curSelObjTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])
curSelShadTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])
def update_obj_label(*_):
upCurrentObjectSel = cmds.ls(sl=True)
upCurrentObjectSelShapes = cmds.listRelatives(upCurrentObjectSel)
upLastobj = upCurrentObjectSelShapes[-1]
objID = cmds.getAttr(upLastobj + '.vrayObjectID')
print objID
cmds.text(curSelObjTxt, e=True, label = objID)
def update_shader_label(*_):
upCurrentShaderSel = cmds.ls(sl=True, type= shaderTypes)
upCurrentShaderSelLast = upCurrentShaderSel[-1]
shadID = cmds.getAttr(upCurrentShaderSelLast + '.vrayMaterialId')
cmds.text(curSelShadTxt, e=True, label = shadID)
print shadID
cmds.scriptJob(event=("SelectionChanged", update_obj_label), p= curSelObjTxt)
cmds.scriptJob(event=("SelectionChanged", update_shader_label), p= curSelShadTxt)
cmds.showWindow(idManagerUI)
Edit:
still your latest version of the script produces the error from time to time.
Also, I noticed in my own version of it, that it sometimes works lovely, then not at all, once I e.g. switched my active window to Firefox or so and then get back to Maya, and sometimes it does not work at all. That is with just one of the functions in my script. With both of them (s.below) it is totally unusable. Very unstable results.
import maya.cmds as cmds
def curSelTxtShower():
idManagerUI = cmds.window(title='Vray ID Manager', s = False, wh = (305,500))
cmds.columnLayout(adj = True)
cmds.text (l = '__________________________________________ \n your current selection has this ID: \n')
curSelObjTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])
curSelShadTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])
def update_obj_label(*_):
upCurrentObjectSelShapes = cmds.listRelatives(s=True) or ["nothing selected"]
upLastobj = upCurrentObjectSelShapes[-1]
if upLastobj is not "nothing selected":
if cmds.attributeQuery('vrayObjectID', node = upLastobj, ex = True) is True:
objID = cmds.getAttr(upLastobj + '.vrayObjectID')
cmds.text(curSelObjTxt, e=True, label = objID)
else:
cmds.text(curSelObjTxt, e=True, label = 'curSel has no ObjID assigned')
def update_shader_label(*_):
upCurrentShaderSel = cmds.ls(sl=True, type= shaderTypes)
upCurrentShaderSelLast = upCurrentShaderSel[-1]
if cmds.attributeQuery('vrayMaterialId', node = upCurrentShaderSelLast, ex = True) is True:
shadID = cmds.getAttr(upCurrentShaderSelLast + '.vrayMaterialId')
cmds.text(curSelShadTxt, e=True, label = shadID)
print shadID
else:
cmds.text(curSelShadTxt, e=True, label = 'curSel has no MatID assigned')
cmds.scriptJob(event=("SelectionChanged", lambda *x: update_obj_label()), p= curSelObjTxt)
cmds.scriptJob(event=("SelectionChanged", lambda *x: update_shader_label()), p= curSelShadTxt)
cmds.showWindow(idManagerUI)
curSelTxtShower()
You need to use a scriptJob to watch for selection change events and respond. You'll want to parent the scriptJob to a particular piece of UI so it deletes itself when the UI object goes away.
An absolutely minimal example looks like this:
import maya.cmds as cmds
wind = cmds.window()
col = cmds.columnLayout()
txt = cmds.text(label="", width = 240)
def update_label(*_):
cmds.text(txt, e=True, label = str(cmds.ls(sl=True)))
cmds.scriptJob(event=("SelectionChanged", update_label), p= txt)
cmds.showWindow(wind)
Edit
This version of OP's code helps avoid the false error message. the actual error was happening when due to an empty selection - but the scriptJob falsely reports it in the previous line:
def scoped():
idManagerUI = cmds.window(title='Vray ID Manager', s = False, wh = (305,500))
cmds.columnLayout(adj = True)
cmds.text (l = '__________________________________________ \n your current selection has this ID: \n')
curSelTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])
def update_label(*_):
# listRelatives works off the current selection already
upCurrentObjectSelShapes = cmds.listRelatives(s=True) or ["nothing selected"]
upLastobj = upCurrentObjectSelShapes[-1]
cmds.text(curSelTxt, e=True, label = upLastobj)
cmds.showWindow(idManagerUI)
cmds.scriptJob(event=("SelectionChanged", update_label), p= idManagerUI)
scoped()