accessing object values using variable as a key - dart

I'm trying to access a class value by using a variable previously defined in dart, but I keep getting the error the operator [] isn't defined for the class
In Javascript I would access an object value using a variable like this:
let movie = {
movieTitle : 'Toy Story',
actor: 'Tom Hanks'
}
let actorName = 'actor';
console.log(movie[actorName]); // <- what I'm trying to replicate in dart
// expected output: Tom Hanks
Here is what I've tried and is throwing that error
class Movie {
String name;
String actor;
String producer;
}
void main() {
var movieTitle = new Movie();
movieTitle.name = 'Toy Story';
movieTitle.actor = 'Tom Hanks';
print(movieTitle.actor); <- prints out Tom Hanks as expected
var actorName = 'actor';
print(movieTitle[actorName]); <- throws error
}
I expect to be able to use a variable on the fly to access the value.
A trivial use case for me would be if I had a a list of Movie classes, where some actors and producers are null, I would like to filter on either non null actors or producer with a function like so:
List values = movieList.where((i) => i.actor != "null").toList(); // returns all Movies in movieList where the actor value isn't the string "null"
var actorIsNull = 'actor';
List values = movieList.where((i) => i[actorisNull] != "null").toList(); // throws error

You can createn a toMap() function in your Movie class and access properties using [] operator
class Movie {
String name;
String actor;
String producer;
Map<String, dynamic> toMap() {
return {
'name': name,
'actor' : actor,
'producer' : producer,
};
}
}
Now Movie class properties can be accessed as:
Movie movie = Movie();
movie.toMap()['name'];

You cannot access class members by a string containing their name. (Except with mirrors - outside the scope of this answer.)
You could remove the class altogether and just use a Map<String, String>.
Map<String, String> movie = {
'movieTitle': 'Toy Story',
'actor': 'Tom Hanks',
}
You could add some bool methods on the class.
bool hasNoActor() => actor == null;
...
List values = movieList.where((m) => !m.hasNoActor()).toList();
Or, you could pass a lambda to your mapper.
Movie movieTitle = Movie()
..name = 'Toy Story'
..actor = 'Tom Hanks';
Function hasActor = (Movie m) => m.actor != null;
List values = movieList.where(hasActor).toList();

Related

Groovy: Dynamic nested properties [duplicate]

I am wondering if I can pass variable to be evaluated as String inside gstring evaluation.
simplest example will be some thing like
def var ='person.lName'
def value = "${var}"
println(value)
I am looking to get output the value of lastName in the person instance. As a last resort I can use reflection, but wondering there should be some thing simpler in groovy, that I am not aware of.
Can you try:
def var = Eval.me( 'new Date()' )
In place of the first line in your example.
The Eval class is documented here
edit
I am guessing (from your updated question) that you have a person variable, and then people are passing in a String like person.lName , and you want to return the lName property of that class?
Can you try something like this using GroovyShell?
// Assuming we have a Person class
class Person {
String fName
String lName
}
// And a variable 'person' stored in the binding of the script
person = new Person( fName:'tim', lName:'yates' )
// And given a command string to execute
def commandString = 'person.lName'
GroovyShell shell = new GroovyShell( binding )
def result = shell.evaluate( commandString )
Or this, using direct string parsing and property access
// Assuming we have a Person class
class Person {
String fName
String lName
}
// And a variable 'person' stored in the binding of the script
person = new Person( fName:'tim', lName:'yates' )
// And given a command string to execute
def commandString = 'person.lName'
// Split the command string into a list based on '.', and inject starting with null
def result = commandString.split( /\./ ).inject( null ) { curr, prop ->
// if curr is null, then return the property from the binding
// Otherwise try to get the given property from the curr object
curr?."$prop" ?: binding[ prop ]
}

How to create a custom Grails query

I'm new to Grails and I've some troubles with queries. I got two domain classes like this:
class Cliente {
String nombre
String cuit
String localidad
String establecimiento
static hasMany = [facturas: Factura]
}
class Factura {
String Proveedor
int sucursal
String numero
String letraFactura
Cliente cliente
Date fecha
String tipo
}
I want to list all elements in facturas with client name:
Result expected:
Proveedor|sucursal|numero|cliente_nombre|fecha
I've tried some different ways but always get the cliente_id not cliente_nombre.
I think I know what you are asking: given a client name, return a list of factura's, with the stipulation that the list of fields should contain the client name rather than the client id.
import org.hibernate.criterion.CriteriaSpecification
// given a client name
def clientNameToSearch = 'some name'
def crit = Factura.createCriteria()
def results = crit.list() {
createAlias('cliente', 'cli')
eq('cli.nombre', clientNameToSearch)
// optional transformer to output a map rather than a list
resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
projections {
property('Proveedor', 'Proveedor')
property('sucursal', 'sucursal')
property('numero', 'numero')
property('cli.nombre', 'clienteNombre')
property('fecha', 'fecha')
}
}
results would then contain a list of maps, with each map having this structure:
[
Proveedor: ...,
sucursal: ...,
numero: ...,
clienteNombre: ...,
fecha: ...
]

Default node type for Node<T>

I am starting to investigate the use of Neo4j using the neo4client API.
I have created a basic database, and can query it using the web client. I am now trying to build a sample C# interface. I am having some problems with index lookups. My database consists of nodes with two properties: conceptID and fullySpecifiedName. Auto-indexing is enabled, and both node properties are listed in the node_keys_indexable property of neo4j.properties.
I keep getting IntelliSense errors in my C# when using the Node class. It appears to be defined as Node<T>, but I don't know what to supply as the value of the type. Consider this example from this forum...
var result = _graphClient
.Cypher
.Start(new
{
n = Node.ByIndexLookup("index_name", "key_name", "Key_value")
})
.Return((n) => new
{
N = n.Node<Item>()
})
.Results
.Single();
var n = result.N;
Where does the "Item" in Node<Item> come from?
I have deduced that the index name I should use is node_auto_index, but I can't figure out a default node type.
Item is the type of node you have stored in the DB, so if you have you're storing a class:
public class MyType { public int conceptId { get; set; } public string fullySpecifiedName { get;set; } }
You would be retrieving Node<MyType> back.
Simple flow:
//Store a 'MyType'
_graphClient.Create(new MyType{conceptId = 1, fullySpecifiedName = "Name");
//Query MyType by Index
var query =
_graphClient.Cypher
.Start(new { n = Node.ByIndexLookup("node_auto_index", "conceptId", 1)
.Return<Node<MyType>>("n");
Node<MyType> result = query.Results.Single();
//Get the MyType instance
MyType myType = result.Data;
You can bypass the result.Data step by doing .Return<MyType>("n") instead of Node<MyType> as you'll just get an instance of MyType in that case.

Sorting list or getAll in Grails

I wanted to implement a default sort order in my domain class and immediately found it didn't work with the getAll method. No biggie, I just used list instead. The thing is that the default sort order in a domain class does not allow you specify multiple sort fields (as seen here).
My goal is to sort all Foo objects first by the name of their Bar object, then by their own name.
class Foo {
String name
String Bar
}
class Bar {
String name
}
How can I implement this in the domain class so I don't have to specify a long/nasty comparator every time I call .list()?
One of my attempts:
static Comparator getComparator() {
def c = { a, b ->
def result = a.bar.name.compareTo( b.bar.name );
if ( result == 0 ) {
result = a.name.compareTo( b.name );
}
}
return c as Comparator
}
Then I could just call Foo.list(Foo.getComparator())... if I could get it to work.
Update:
I think I am really close here, just having trouble with implementing two comparisons in the same sort closure.
Foo.list().sort{ a, b ->
def result = a.bar.name <=> b.bar.name;
// Things mess up when I put this if statement in.
if( result == 0 ) {
a.name <=> b.name
}
}
Disco!
class Foo { // My domain class
// ...
static Comparator getComparator() {
def c =[
compare: { a, b ->
def result = a.bar.name <=> b.bar.name;
if( result == 0 ) {
result = a.name <=> b.name
}
return result
}
] as Comparator
}
// ...
}
And implemented like this in my controller:
Foo.list().sort( Foo.getComparator() )
PS:
The above works, but Jeff Storey posted some code in his answer after I discoed, and his code works and is much nicer than mine so use it :)
In your case, would it make sense to have Foo implement Comparable and the implementation could do the comparison as you described? Then when you sort the objects in a list, because they are Comparable, they will sort properly.
If it does not make sense for you to implement Comparable though, you will need to specify a comparator to sort by.
Here's some sample code based on your comments:
edit:
class Person implements Comparable<Person> {
String firstName
String lastName
int compareTo(Person other) {
int lastNameCompare = lastName <=> other.lastName
return lastNameCompare != 0 ? lastNameCompare : firstName <=> other.firstName
}
String toString() {
"${lastName},${firstName}"
}
}
def people = [new Person(firstName:"John",lastName:"Smith"), new Person(firstName:"Bill",lastName:"Jones"), new Person(firstName:"Adam",lastName:"Smith")]
println "unsorted = ${people}"
println "sorted = ${people.sort()}"
This prints:
unsorted = [Smith,John, Jones,Bill, Smith,Adam]
sorted = [Jones,Bill, Smith,Adam, Smith,John]
To further simplify the above post (I would have commented on it but I don't have the rep yet), you can chain the groovy compare operators using the elvis operator:
class Person implements Comparable<Person> {
String firstName
String lastName
int compareTo(Person other) {
return lastName <=> other.lastName ?: firstName <=> other.firstName
}
String toString() {
"${lastName},${firstName}"
}
}
def people = [new Person(firstName:"John",lastName:"Smith"), new Person(firstName:"Bill",lastName:"Jones"), new Person(firstName:"Adam",lastName:"Smith")]
println "unsorted = ${people}"
println "sorted = ${people.sort()}"
This will give you the same result because 0 is considered false in groovy's eyes, which will make it look at the next conditional in the chain.

LuaInterface: add a table to the script scope

Question: how can I insert a table from C# into 'LuaInterface' script scope using a C# object (preferably anonymous type)?
/// I want to do this, but it does not work
/// (complains that 'test' is userdata and not table
/// when I pass it to pairs() in the script)
//lua["test"] = new { A = 1, B = 2 };
/// another option
/// but building this string is a PITA (actual string is nested and long).
lua.DoString("test = { A = 1, B = 2 }");
// So I have to do this
lua.NewTable("test");
((LuaTable) lua["test"])["A"] = 1;
((LuaTable) lua["test"])["B"] = 2;
lua.DoString("for k,v in pairs(test) do print(k..': '..v) end");
You could fill a C# Dictionary with the keys and values you want to put inside the table. Then do what you're doing in the "I have to..." section, but inside a foreach loop.
Untested code:
var test = new Dictionary<string, int> {
{ "A", 1 },
{ "B", 2 }
};
foreach (var entry in test)
{
((LuaTable) lua]["test"])[entry.Key] = entry.Value;
}
I'd refactor this basic idea into a generic class for added flexibility.
I think if you want to serialize anonymous types into lua tables you will need to user reflection. Maybe you can try to write a lua table serializer. I think I would try to assemble my tables as string and pass it to Lua with DoString
I think the dictionary solution is good and you can use nested tables with without reflection. I tried Tuples, but they are not generic enough and eventually I fell back to the reflection idea.
I would create an extension method:
public static class LuaExt
{
public static LuaTable GetTable(this Lua lua, string tableName)
{
return lua[tableName] as LuaTable;
}
public static LuaTable CreateTable(this Lua lua, string tableName)
{
lua.NewTable(tableName);
return lua.GetTable(tableName);
}
public static LuaTable CreateTable(this Lua lua)
{
lua.NewTable("my");
return lua.GetTable("my");
}
}
Then I could write something like this:
var lua = new Lua();
var table = lua.CreateTable("test");
table["A"] = 1;
table["B"] = 1;
table["C"] = lua.CreateTable();
((LuaTable) table["C"])["A"] = 3;
table["D"] = lua.CreateTable();
((LuaTable)table["D"])["A"] = 3;
foreach (var v in table.Keys)
{
Console.WriteLine(v + ":" + table[v]);
}

Resources