Modifying NSMutableDictionary by key path - ios

I have a NSDictionary with nested NSDictionary/NSArray (Generated through a JSON).
I need to remove objects in multiple places according to some logic imposed on me.
For instance lets say that the dictionary has some structure like:
{
"Array1" : [
{
"InnerArray1" : [
{
"some conditional field" : Evaluate this ...
}
],
"More Properties : ....
}
],
"Array2" : {
... some complex inner structure
{
// some inner object to remove according to "evaluate condition"
}
}
}
When I iterate the "Array1.InnerArray1..." and evaluate some condition to true , I need to remove objects in a disjoint location.
Ideally I could do something like
foreach item in Array1.InnerArray1 {
if item evaluates to true {
// evaluate the disjoint location...
remove Array2.....InnerObject(s) where ConditionField == true
}
}
Currently it is very awkward to iterate the inner objects and mutate them on the same pass (and very hard to read).
Given I have created a deep mutable copy of this whole data tree, is it possible to remove nested objects using kvc or another mechanism without nested iterations?

Related

How to find an object by a property from a List of List of objects in dart?

Hello I am new to dart and trying to find an item by property name in a list of list.
class Product{
String id;
String title;
Product(this.id,this.title);
}
void main(){
List<List<Product>> allProdcuts=[
//New Prodcuts
[
Product("1","Hammer"),
Product("3","Nails"),
Product("2","Screws"),
],
futureItems,
//Old Prodcuts
[
Product("4","Rock"),
Product("5","Paper"),
Product("6","Scissor"),
],
//Rare Items
[
Product("7","Plank"),
Product("8","Wires"),
Product("9","Box"),
],
];
print(allProdcuts.where((itemsList)=>itemsList.contains((product)=>product.title='Wires')));
//Returns ()
}
I have tried using for a single List:
List<Product> futureItems= [
Product("101","Galactic Hammer"),
Product("301","Galactic Nails"),
Product("201","Galactic Screws"),
];
print(newProduct.firstWhere((p)=>p.title=='Hammer'));
//Instance of 'Product'
Also tried this:
print(allProdcuts.map((itemList)=>itemList.firstWhere((p)=>p.title=='Nails')));
// Bad state: No elementError: Bad state: No element.
But there is an element with the title='Nails'.I don't understand what I am doing wrong.
You are calling itemList.firstWhere((p)=>p.title=='Nails') on each list, also the ones with no element with title "Nails". Since firstWhere throws if there is no matching value, it does that for two of your three lists. Also, in the example, itemsList.contains(...) does not take a callback, so you are just checking whether a function is in the list, which it isn't. You might want to use any for that, but it won't solve the problem here.
To do this efficiently, I'd probably create helper function:
Product findByTitle(List<List<Product>> allProducts, String title) {
for (var products in allProducts) {
for (var product in products) {
if (product.title == title) return product;
}
}
// Or return `null`.
throw ArgumentError.value(title, "title", "No element with that title");
}
The return in the middle allows you to skip out of the double iteration the moment you have a match, something which is harder to do with firstWhere/map/forEach etc.
One alternative solutions would be:
var product = allProducts.expand((l) => l.where((p) => p.title == title)).first;
which finds all the products with the given title and flattens them into a single iterable, then picks the first one (if there are any). Because iterables are lazy, it will actually stop at the first match.
There are many ways to solve this.
One example is to use the forEach() method:
allProdcuts.forEach(
(List<Product> l)=>l.forEach(
(Product p){
if (p.title=="Nails")
print(p.id);
}
)
);
The for each method receives a function and applies this function to every element on the list. If you have a lists of lists, you can do this twice to get a function applied to each element of the sub lists.
The above code prints 3, which is the desired result.
Another solution would be to flatten the list first, so you can have an easier search later.
print(allProdcuts.any((innerListOfProducts) =>
innerListOfProducts.any((product) => product.title == 'Wires')));
This code will return true if 'Wires' is in the inner list, and false otherwise.

Rails array style nested parms

So I have objects that I'm trying to pass to a json-acccepting restful interface using parms and #connection, but the source object and the target are in different formats, so I need to rename them.
So I'm trying to do something like this:
parms = {
:foo => anBunchOfBars.bar[
:barID => bar.Identifier
:bartab => bar.finances.owed
:barbell => bar.equipment.first
]
}
... to generate an outgoing JSON similar to the following:
{
"foo": [
{
"barID": "Irish Pub",
"bartab": "30 Yen",
"barbell": "Of the ball."
},
{
"barID": "One Gold Bar",
"bartab": "100 cents",
"barbell": "fry."
}
]
}
But I can't find the proper syntax. Examples I've found seem to only cycle through a core list and leave out naming items on nested traits (or skip nested traits entirely), and I haven't seen anything that shows how to pull values from a looped item.
What's the proper syntax to format the parms value?
Assuming that anBunchOfBars is an array of bars:
bars = anBunchOfBars.map do |bar|
{
barID: bar.Identifier
bartab: bar.finances.owed
barbell: bar.equipment.first
}
end
params = { foo: bars }

iOS Swit 3 - filter array inside filter

I would like to filter array inside a filter. First I have a big array of Staff object (self.bookingSettings.staffs). Inside this array I have multiple object like this :
"staffs": [
{
"id": 1,
"name": "Brian",
"services": [
{
"id": 1
},
{
"id": 2
},
{
"id": 3
},
{
"id": 4
}
],
"pos": 1
},...
I would like to filter this array in order to have only services with id = 3.
I succeed to have if first object is equal to 3 with this code :
self.bookingSettings.staffs.filter({ $0.services.first?.id == self.bookingService.id })
but that takes only the first item.
I think I have to filter inside my filter function, something like this to loop over all object inside services :
self.bookingSettings.staffs.filter({ $0.services.filter({ $0.id == self.bookingService.id }) })
but I've the following error: Cannot convert value of type [BookingService] to closure result type Bool.
Is this a good idea ? How can I achieve this ?
You could use filter, which would look something like this:
self.bookingSettings.staffs.filter {
!$0.services.filter{ $0.id == self.bookingService.id }.isEmpty
}
This code is constructing an entire array of filtered results, only to check if its empty and immediately discard it. Since filter returns all items that match the predicate from the list, it won't stop after it finds a match (which is really what you're looking for). So even if the first element out of a list of a million elements matches, it'll still go on to check 999,999 more elements. If the other 999,999 elements also match, then they will all be copied into filter's result. That's silly, and can use way more CPU and RAM than necessary in this case.
You just need contains(where:):
self.bookingSettings.staffs.filter {
$0.services.contains(where: { $0.id == self.bookingService.id })
}
contains(where:) short-circuits, meaning that it won't keep checking elements after a match is found. It stops and returns true as soon as find a match. It also doesn't both copying matching elements into a new list.

Firebase Security Rules: .indexOn unique ids

I have this structure:
"post": {
"groupMember": {
"-KHFHEHFWDB1213": "true",
"-KSJHDDJISIS011": "true",
"-KJSIO19229129k": "true"
}
}
I want to .indexOn the auto-generated unique groupMember ids.
I tried doing this:
"post": {
".indexOn": "groupMember"
...
}
But I'm still getting this error:
Consider adding ".indexOn": "groupMember/-KHFHEHFWDB1213" at /post
So how do I add a .indexOn on a unique id?
UPDATE:
This is the query I use (in Swift):
postRef.queryOrderedByChild("groupMember/\(uid)").queryEqualToValue(true).observeEventType(.Value, ... )
To query whether or not one of the given keys has value "true" (note that as typed your data structure is a string, not a boolean -- something to look out for!) you'll want to create security rules like so:
{
"post": {
"groupMember": {
"$memberId": {".indexOn": ".value"}
}
}
}
And then use queryOrderedByValue("true") on the /post/groupMember path. Important to note is $memberId in the rules, which declares a wildcard key representing your autogenerated ids, and .value, which indicates that rather than indexing on a child property (if your structure had another layer of nesting) you want to index on the immediate leaf node value.

Grails namedQuery sort order by multiple columns

Given a namedQuery:
class MyDomainObject {
String someProperty
static namedQueries = {
myNamedQuery {
// some implementation here
}
}
}
I can use it to generate a list, sorted by a single key, like this (documentation for 2.4.3 here):
def resultsList = MyDomainObject.myNamedQuery.list(sort: "someProperty", order: "desc")
How do I order the results by multiple columns? I'd like to be able to define the sort parameters dynamically, not define them in the query.
I'm sure there's a better way, but I ended up creating another named query that I can concatenate onto my chosen one (I could always incorporate into the original query too).
// expects to be passed a List containing a series of Maps
orderByMultipleColumns { List columnsToSortBy ->
columnsToSortBy.each { Map field ->
order("${field.fieldName}", field.fieldOrder)
}
}
// usage:
List orderByList = []
// ...
// within some loop that I use:
orderByList << [fieldName: someValue, fieldOrder: dir] // dir == 'asc' or 'desc'
// ...
MyDomainObject.myNamedQuery().orderByMultipleColumns(orderList).listDistinct(max: length, offset: start)

Resources