In handlebars.net, I know we can access array members like
{{SomeArray.0}}
Is it possible to access collection items through indexers like
{{SomeCollectionInstance['key']}}
or
{{SomeCollectionInstance.key}}
If not possible, can anyone propose a way to implement it, at least for string and numeric indexers?
For dictionaries and objects, the .keyName or .propertyName notations are supported.
You can also use .[key name] or .[property name] (square brackets) - this is useful for situations where the property name has a weird character in it, like a space.
Related
Most of what I know is Javascript. I believe "Lists" are the closest thing Dart has to Arrays, but are they technically the same thing? Is it wrong to think of them as Arrays? Similarly, would Maps be considered Objects? I realize there are likely differences, but would it be "wrong" to make that comparison?
JavaScript Array objects are similar to Dart growable List objects. Both can be added to and accessed by index. Dart lists can only be accessed by index, where JavaScript lists are full JavaScript objects (see below), it just has a magic length property that is only updated when using integer-named properties. In practice, use a Dart List where you would have used a JavaScript Array.
JavaScript Objects are a combination of multiple things. They are mappings from string names to values - that part is best simulated by a Dart Map<String, Object>. They also allow prototype based inheritance, and if you are using that, you probably want to define a Dart class instead. As a data structure, use a Dart Map where you would have used a JavaScript {} object.
Everything is an object in Dart.
EVERYTHING
Everything in Dart is an Object - a List, a Map, even an int:
https://www.dartlang.org/guides/language/language-tour#important-concepts
Dart has Lists which are ordered sequences of objects. There is no class or interface called Array, though Lists act extremely similar to Arrays you might have encountered in other programming languages.
Everything in Dart is an Object.
List is pretty close to JS Array.
Map is somewhat related to Object in JS, but not quite.
A map is just to store keys and values together, but in Dart you can have non-string keys. There are also no prototypes or similar for maps in Dart.
let dict = [1:"One", 2:"Two", 3:"Three"]
let values = dict.values
print(values.dynamicType)
prints:
LazyMapCollection<Dictionary<Int, String>, String>
There are two things I don't understand here. Wouldn't it be a bit more simple if values returned an Array? Also, what is LazyMapCollection? I looked into Apple's reference but it provides literally no information (or nothing I am able to make sense of).
You can iterate over this object, because it is CollectionType:
for v in values {
print(v)
}
prints:
Two
Three
One
But for some reason Apple didn't use Array type.
A LazyMapCollection is a lazy (only evaluated if necessary) view on a collection. By "view" I mean "window", "frame", "virtual subset", this kind of concept.
To get the actual values from it, just use the Array initializer:
let values = dict.values
let result = Array(values)
You have here a serious speed optimisation. Creating an array is expensive. Instead you get an instance of some strange class that behaves in every way like an array. However, it doesn't have its data stored in a real array, instead it access the data from a dictionary.
Say you have a dictionary with 10,000 string values. You don't want iOS to copy all the 10,000 string values when you call dict.values, do you? That's what this class is there for, to prevent copying 10,000 strings. A real array would force copying.
And anyway, with your username you are asking for things like this, and Apple provides many examples. That's how they make iOS fast.
Both arrays and dictionaries are value types (structs). That means that once you request an array, the values must be copied. If Dictionary.values were returning an array, this could be a performance expensive operation - and one that is usually not needed because most of the times you want only to iterate over the values.
So, to use a special (lazy) collection type is basically a way to prevent copying when the copying is not needed. If you want a copy, you have to ask for it explicitly.
Say I have a NSArray, and each item is an NSDictionary with three keys keyA, keyB, and keyC - each referring to objects of unknown type (id).
If I wanted to write a method that found the given element with those three keys i.e.
-(NSDictionary *) itemThatContainsKeys:(id)objectA and:(id)objectB and:(id)objectC
would I run into trouble by simply enumerating through and testing object equality via if([i objectForKey:(keyA) isEqualTo:objectA]) etc? I would be passing in the actual objects that were set in the dictionary initialization - ie not strings with the same value but different locations.
Is this bad practise?
Is there a better way to do this without creating a database?
You can override isEqual to stipulate the notion of equality for your type. The same rules apply as in other languages:
If you provide an implementation of equals you should provide an implementation of 'hash'
Objects that are 'equal' should have the same 'hash'
Equals should be transitive -> if A equals B, and B equals C, then C must equal A.
Equals should be bi-directional -> if A equals B, then B must equal A.
This will ensure predictable behavior in classes like NSSet, that use hash for performance, falling back to equals on when there's a collision.
As Jason Whitehorn notes, Objective-C also has the convention of providing another isEqualToMyType method for convenience.
AppCode, EqualsBuilder, Boiler-plate code
It would be nice if there was something like Apache's 'EqualsBuilder' class, but in the meantime AppCode does a fine job of implementing these methods for you.
The isEqual: method compares object identity unless overwritten by a subclass. Depending on what class the target is, this May or may not be what you want. What I prefer is to use a more class specific comparison like isEqualToNumber: simply because of it's explicitness. But, isEqual should work depending on the target.
Other than that, and not knowing more specifics of what you're doing, it's hard to say if there is a better way to accomplish what you're after. But, here are my thoughts;
An array of a dictionary almost sounds like you might need a custom class to represent some construct in your app. Perhaps the dictionary could be replaced with a custom object on which you implement an isEqualToAnotherThing: method. This should simplify your logic.
I have done a lot of research on this topic and am still stumped. I've previously asked this question to stackOverflow and recieved a less than satisfactory response. This leads me to believe that this is a rather advanced topic needing a strong understanding of the CLR to answer. I'm hoping a guru can help me out.
This question is largely based on my previous posts found here and here.
I'm attempting to recreate some of the functionality of the SOS.dll using reflection. Specifically the ObjSize and DumpObject commands. I use reflection to find all the fields and then if the fields are primitive types I add the size of the primitive type to the overall size of the object. If the field is a value type, then I recursively call the original method and walk down the reference tree until I've hit all primitive type fields.
I'm consistently getting object sizes larger than SOS.dll ObjSize command by a factor of two or so. One reason I've found is that my reflection code seems to be finding fields that SOS is ignoring. For example in a Dictionary, SOS find's the following fields:
buckets
entries
count
version
freeList
freeCount
comparer
keys
values
_syncRoot
m_siInfo
However my reflection code finds all of the above and also finds:
VersionName
HashSizeName
KeyValuePairsName
ComparerName
A previous answer implied that these were constants and not fields. Are constants not held in memory? Should I be ignoring constants? I'm not sure which binding flags to use to get all fields other than constants also...
Also, I'm getting confused regarding the inconsistencies found in the SOS ObjSize and DumpObject commands. I know DumpObject doesn't look at the size of the referenced types. However when I call Object size on the dictionary mentioned above I get:
Dictionary - 532B
Then I call DumpObject on the Dictionary to get the memory address of it's reference types. Then when I call Objsize on it's reference types I get:
buckets - 40
entries - 364
comparer - 12
keys - 492
(the rest are null or primitive)
**Shouldn't the ObjSize on the top level dictionary roughly be the sum of all the ObjSizes on fields within the dictionary? Why is Reflection finding more fields that DumpObject? Any thoughts on why my reflection analysis is returning numbers larger than SOS.dll? **
Also, I never got an answer to one of my questions asked in the thread linked above. I was asking whether or not I should ignore properties when evaluating the memory size of an object. The general consensus was ignore them. However, I found a good example of when a property's backing field would not be included in the collection returned from Type.GetFields(). When looking under the hood of a String you have the following:
Object contains Property named FirstChar
Object contains Property named Chars
Object contains Property named Length
Object contains Field named m_stringLength
Object contains Field named m_firstChar
Object contains Field named Empty
Object contains Field named TrimHead
Object contains Field named TrimTail
Object contains Field named TrimBoth
Object contains Field named charPtrAlignConst
Object contains Field named alignConst
The m_firstChar and m_stringLength are the backing fields of the Properties FirstChar and Length but the actual contents of the string are held in the Chars property. This is an indexed property that can be indexed to return all the chars in the String but I can't find a corresponding field that holds the characters of a string.
Any thoughts on why that is? Or how to get the backing field of the indexed property? Should indexed properties be included in the memory size?
While this idea is interesting I believe it is ultimately futile as Reflection doesn't provide access to the actual storage of objects. Reflection lets you query types, but not their actual memory representation (which is an implementation detail of the CLR).
For reference types the CLR itself adds internal fields to each instance (MT and syncblk). These are not surfaced by the Reflection APIs. Additionally the CLR may use any kind of padding/compacting on the storage of the fields depending on the definition of the type. What this means is that size of primitive types may not be consistent across different reference types. Reflection doesn't allow you to discover this either.
In short Reflection is unable to discover a lot of details needed to produce correct results.
I have searched through all the questions, but did not find an answer yet. The closest I came to was this Passing an array to sqlite WHERE IN clause via FMDB? . However, the answer suggested did not seem to work. The command does not throw any error, however it does not perform the intended operation (e.g. DELETE) either.
Here's what I am trying to do :
[myDB executeUpdateWithFormat:#"DELETE FROM table WHERE row_id IN (%#)",rowIdsToBeDeleted];
rowIdsToBeDeleted is a comma seperated NSString containing rowIds as NSNumber objects, e.g.
1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012
I even tried using the executeUpdate, but no luck.
Could any of you please help ?
You could do simply:
[myDB executeUpdate:[NSString stringWithFormat:#"DELETE FROM table WHERE row_id IN (%#)",rowIdsToBeDeleted]];
Despite what one might otherwise infer from the method name, the executeUpdateWithFormat method does not perform traditional printf-style formatting. Behind the scenes, what it really does is iterate through the format strings, replacing the printf-style strings with ? placeholders, and then try to the appropriate sqlite3_bind_xxx function to bind the values to those placeholders.
This implementation of executeUpdateWithFormat introduces all sorts of subtle issues. (Because of this, it is likely to be deprecated in future FMDB versions.) In this particular case, the problem is that sqlite3_bind_xxx can not bind a comma separated string as an array of values to be bound to a single ? placeholder.
Generally one should avoid using stringWithFormat (or Swift string interpolation) to build SQL statements to be passed to FMDB or SQLite because if done improperly, you can be exposed to SQL injection attacks and/or fail if you fail to properly escape string values. But this example, where you want to test to see if some numeric value is within a set of numeric values, is an exception to that rule and you can use stringWithFormat as shown above.
If that method is anything like the NSPredicate syntax, simply remove the parenthesis (they are handled for you (and pass in a collection instead of a string):
NSArray *ids = [rowIdsToBeDeleted componentsSeparatedByString:#","];
[myDB executeUpdateWithFormat:#"DELETE FROM table WHERE row_id IN %#",ids];
edit
Also, usually you pass in an actual collection object (not a string)... above edited to reflect