In D, I'm trying to create an enum whose members have members. I can better explain what I'm trying to do with an example, where s and i stand in for the sub-members I'm trying to create:
In Python, I can do this:
class Foo(enum.Enum):
A = "A string", 0
B = "B string", 1
C = "C string", 2
def __init__(self, s, i):
self.s = s
self.i = i
print(Foo.A.s)
Java can do something like this:
public enum Foo {
A("A string", 0),
B("B string", 1),
C("C string", 2);
private final String s;
private final int i;
Foo(String s, int i) {
this.s = s;
this.i =i;
}
}
How do I do this in D? I don't see anything in the official tutorial. If for whatever reason I can't do this in D, what's a good alternative?
You can build an enum with any type, here we use a tuple (much like python) with a little alias for it to be easier to type.
import std.stdio;
import std.typecons;
alias FooT = Tuple!(string, "s", int, "i");
enum Foo : FooT {
A = FooT("A string", 0),
B = FooT("B string", 1),
C = FooT("C string", 2),
}
void main(string[] args) {
writeln(Foo.A.s);
}
Related
I get the error:
Exception in thread "main" com.google.gson.JsonParseException:
Expecting object found: "com.shagie.app.SimpleMap$Data#24a37368"
when trying to deseralize a Map that uses non-trivial keys:
package com.shagie.app;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.HashMap;
public class SimpleMap {
public static void main(String[] args) {
Wrapper w = new Wrapper();
w.m.put(new Data("f", 1), new Data("foo", 3));
w.m.put(new Data("b", 2), new Data("bar", 4));
GsonBuilder gb = new GsonBuilder();
gb.setPrettyPrinting();
Gson g = gb.create();
String json = g.toJson(w);
System.out.println(json);
w = g.fromJson(json, Wrapper.class);
System.out.println(w.m.isEmpty());
}
static public class Wrapper {
HashMap<Data, Data> m = new HashMap<Data, Data>();
}
static public class Data {
String s;
Integer i;
public Data(String arg, Integer val) { s = arg; i = val; }
}
}
This serializes to the json:
{
"m": {
"com.shagie.app.SimpleMap$Data#24a37368": {
"s": "foo",
"i": 3
},
"com.shagie.app.SimpleMap$Data#66edc3a2": {
"s": "bar",
"i": 4
}
}
}
One can see the key attempting to be serialized, but certainly not in a way that can be deserialized.
How does one serialize this object so that it can be deserialized?
I found the following while trying to solve this puzzle: Issue 210: Cannot serialize or deserialize Maps with complex keys.
For any internet travelers from the future (like myself)... you can enable this functionality in GSON 2.* with the enableComplexMapKeySerialization() method on GsonBuilder.
Here's the javadoc for that method.
When enabled, the map will be serialized (and correctly deserialized) as an array of [key, value] arrays:
{"m":[[{"s":"f", "i",1}, {"s":"foo", "i":3}], [{"s":"b", "i",2}, {"s":"bar", "i":4}]]}
The problem is that toString() is getting called on the keys to the map, rather than them being serialized themselves.
To fix this a custom serializer and deserializer needs to be set up, and the deserializer needs to be aware of the format that the object uses to display itself as a string (the toString() method must return a string that can be used to reconstruct the entire object).
For the above example:
package com.shagie.app;
import com.google.gson.*;
import java.lang.reflect.Type;
import java.util.HashMap;
public class SimpleMapFixed {
public static void main(String[] args) {
Wrapper w = new Wrapper();
w.m.put(new Data("f", 1), new Data("foo", 3));
w.m.put(new Data("b", 2), new Data("bar", 4));
GsonBuilder gb = new GsonBuilder();
gb.setPrettyPrinting();
gb.registerTypeAdapter(Data.class, new DataSerializer());
Gson g = gb.create();
String json = g.toJson(w);
System.out.println(json);
w = g.fromJson(json, Wrapper.class);
System.out.println(w.m.isEmpty());
}
static public class Wrapper {
HashMap<Data, Data> m = new HashMap<Data, Data>();
}
static public class DataSerializer implements JsonSerializer<Data>,
JsonDeserializer<Data> {
#Override
public Data deserialize(JsonElement je, Type t, JsonDeserializationContext ctx)
throws JsonParseException {
Data rv;
JsonObject jo;
System.out.println("deserialize called with: " + je.toString());
if (je.isJsonObject()) {
jo = je.getAsJsonObject();
rv = new Data(jo.get("s").getAsString(), jo.get("i").getAsInt());
} else {
String js = je.getAsString();
String[] s = js.split(":", 2); // split into two (and only two)
rv = new Data(s[1], Integer.valueOf(s[0]));
}
System.out.println("deserialize returns: " + rv.s + " " + rv.i);
return rv;
}
#Override
public JsonElement serialize(Data data, Type type, JsonSerializationContext jsonSerializationContext) {
JsonObject jo = new JsonObject();
jo.addProperty("s", data.s);
jo.addProperty("i", data.i);
System.out.println("serialize called: " + jo.toString());
return jo;
}
}
static public class Data {
String s;
Integer i;
public Data(String arg, Integer val) { s = arg; i = val; }
#Override
public String toString() {
String rv = i.toString() + ':' + s;
System.out.println("toString called: " + rv);
return rv;
}
}
}
Running this code produces:
serialize called: {"s":"foo","i":3}
toString called: 1:f
serialize called: {"s":"bar","i":4}
toString called: 2:b
{
"m": {
"1:f": {
"s": "foo",
"i": 3
},
"2:b": {
"s": "bar",
"i": 4
}
}
}
deserialize called with: "1:f"
deserialize returns: f 1
deserialize called with: {"s":"foo","i":3}
deserialize returns: foo 3
deserialize called with: "2:b"
deserialize returns: b 2
deserialize called with: {"s":"bar","i":4}
deserialize returns: bar 4
Note the invocations of toString() as part of the serialization. In this code, the logic for the deserializion from the String form is in the DataSerializer, though it may make sense to move it into the Data class as another constructor instead - it doesn't affect the final outcome.
Further note that Data was a rather simple object itself with no deeper structures. Trying to serialize that as the key would require additional work.
Its Up to you how you are maintaining the HahMap Keys, You can deserialized it with simple and easiest way.
final Type typeOf = new TypeToken <Map<String, Map<String, Data>>>(){}.getType();
final Map<String, Map<String, Data>> newMap = gson.fromJson(json, typeOf);
final Map<String, Data> map = newMap.get("m");
final Iterator<Entry<String, Data>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String,Data> pair = (Map.Entry<String,Data>) it.next();
String key = pair.getKey();
System.out.println("key "+ key + " Values[ i= " + data.getI() + ", s= " +data.getS()+" ]");
}
Result:
key = snippet.Snippet$Data#61506150 Values [ i= 3, s= foo ]
key = snippet.Snippet$Data#63ff63ff Values [ i= 4, s= bar ]
I have a JSON with some key-value pairs. I need to pick up by name and process it's value differently. The oder of the process should be same order as the keys listed in the JSON (JSON is unknown, only knows it will have some key and corresponding value, so cant not know the order outside of the JSON).
Simplified sample usage:
String jsonData = "{key1:{some other data}, key2:{sub-key:sub-value}}";
val jsonObject = JSONObject(jsonData)
val names = jsonObject.keys()
if (names.hasNext()) {
val key = names.next()
val valueJson = jsonData.optString(key)
val gson = Gson()
val resultList = ArrayList<Data> () // result should keep the order as the keys in the json
if (key == "key1") {
val parsedResult = gson.fromJson <POJO_1> (valueJson, POJO_1::class.java)
resultList.add(processDataFromKey1(parsedResult))
} else if (key == "key2") {
val parsedResult = gson.fromJson <POJO_2> (valueJson, POJO_2::class.java)
resultList.add(processDataFromKey2(parsedResult))
}
}
The problem is the jsonObject.keys() the order of the keys is undefined.
So how to preserve the order of the keys from the JSON string (don't want to add dependency javax.json:javax.json-api)
org.json.JSONObject internally uses HashMap. They even added some comment to it:
HashMap is used on purpose to ensure that elements are unordered by
the specification. JSON tends to be a portable transfer format to
allows the container implementations to rearrange their items for a
faster element retrieval based on associative access. Therefore, an
implementation mustn't rely on the order of the item.
Use Gson. It uses com.google.gson.internal.LinkedTreeMap implementation for Map. From it's documentation:
A map of comparable keys to values. Unlike TreeMap, this class
uses insertion order for iteration order. Comparison order is only
used as an optimization for efficient insertion and removal.
This implementation was derived from Android 4.1's TreeMap class.
So, for below JSON payload:
{
"status": "status",
"date": "01/10/2019",
"abc": {
"Field1": "value1",
"key": "value2"
},
"rgj": {
"key": "value2",
"Field1": "value3"
},
"name": "Rick"
}
This example app:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Type;
import java.util.Map;
public class GsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
Gson gson = new GsonBuilder().create();
Type type = new TypeToken<Map<String, Object>>() {
}.getType();
Map<String, Object> map = gson.fromJson(new FileReader(jsonFile), type);
map.forEach((k, v) -> {
if (v instanceof Map) {
System.out.println(k);
((Map) v).forEach((k1, v1) -> System.out.println(" " + k1 + " => " + v1));
} else {
System.out.println(k + " => " + v);
}
});
}
}
Prints:
status => status
date => 01/10/2019
abc
Field1 => value1
key => value2
rgj
key => value2
Field1 => value3
name => Rick
Notice that key and Field1 are in different order in abc and rgj objects.
you could use jsonparser rather than jsonreader so you control the event flow.
See https://docs.oracle.com/javaee/7/api/javax/json/stream/JsonParser.html
Note that your question is neither kotlin nor gson specific.
Another thing you can do is refer to the String jsonData in your example and rebuild the order.
Something like:
JSONObject json = new JSONObject(jsonData);
Iterator<String> keys = json.keys();
List<KeyOrder> ordering = new ArrayList();
while(keys.hasNext()) {
String key = keys.next();
int loc = jsonData.indexOf('"' + key + '"');
ordering.add(new KeyOrder(loc, key));
}
Collections.sort(ordering);
for(KeyOrder order: ordering) {
Object value = json.get(order.getKey());
// process the key and value
}
public class KeyOrder implements Comparable<KeyOrder> {
private int order;
private String key;
public KeyOrder(int order, String key) {
this.order = order;
this.key = key;
}
#Override
public int compareTo(KeyOrder o) {
return order - o.getOrder();
}
private int getOrder() {
return order;
}
public String getKey() {
return key;
}
}
What is the naming convention when you have two generic-name methods performing the same operation, while one is immutable and the other is mutable?
EXAMPLE
Consider cellwise operation accepting 2 arrays of numbers: immutable version creates a new array to put the result in, while the mutable version stores the result in first array parameter.
Since the method name is something generic like apply as operation strategy (add, sub, mul, div) is specified by third argument, you can not use common words like add for mutability (a = a + 1) and plus for immutability (c = a + b).
CODE (TO BE SKIPPED)
Following details might be offtopic, but for illustration about what method I'm talking about:
#FunctionalInterface
public interface BinaryOperation { double apply(double a, double b); }
public final class BinaryOperations {
private BinaryOperations() {}
public static final BinaryOperation ADD = (a, b) -> a + b;
public static final BinaryOperation SUB = (a, b) -> a - b;
public static final BinaryOperation MUL = (a, b) -> a * b;
public static final BinaryOperation DIV = (a, b) -> a / b;
}
public final class DoubleArraysMath {
private DoubleArrayMath() {}
// ---> METHOD NAME OF INTEREST
public static void applyAsMutable(double[] a, double[] b, BinaryOperation o) {
apply(a, a, b, o);
}
// ---> METHOD NAME OF INTEREST
public static double[] applyAsImmutable(double[] a, double[] b, BinaryOperation o) {
double[] c = new double[a.length];
return apply(c, a, b, o);
return c;
}
private static void apply(double[] result, double[] a, double[] b, BinaryOperation o) {
for (int i = 0; i < a.length; i++) { result[i] = o.apply(a[i], b[i]); }
}
}
// just an example of usage
double[] r = DoubleArraysMath.applyAsImmutable(a, b, BinaryOperations.MUL);
DoubleArraysMath.applyAsMutable(a, b, BinaryOperations.ADD);
DoubleArraysMath.applyAsMutable(a, b, (ai, bi) -> ai*ai + bi); // some custom operation
SEPARATE CLASSES
Having mutable and immutable methods separated in DoubleArraysMutableMath and DoubleArraysImmutableMath classes avoids writting of "mutable/immutable" prefix/suffix at the begining/end of each method name. Following this pattern, you will end up with any utility class named as "mutable/immutable" (whether it is good or not I will leave as an open question).
SINGLE CLASS PROBLEM
In case we want to have these methods in single class (better maintenance), what is the proper naming "pattern"? Pattern I have used in my code sample "asMutable/asImmutable" or generally "mutable/immutable" might be incompatible with longer method names. Is there any other options?
Edit based on the comments
You should definitely implement mutable and immutable classes separately. Method names can be similar or different, it doesn't matter as interfaces will be different anyway.
Single class
Mutability strategy can be mentioned as an additional argument of the method, for example:
apply(a,b,Operation.ADD, ResultValue.NEW)
apply(a,b,Operation.ADD, ResultValue.FIRST_ARG)
apply(a,b,Operation.ADD, ResultValue.SECOND_ARG)
However, using multiple strategies in a single method will make the method confusing for the clients and error-prone.
If the signature of the method is
double [] apply(double[] arg1, double[] arg2, BinaryOperation)
then mutability or immutability can be part of the BinaryOperation itself:
public class FirstArgMutablePlusOperation {
double[] apply(double[] arg1, double[] arg2) {
//sample mutation
arg1[0] = arg1[0] + arg2[0];
// still return arg1 as a result
return arg1;
}
}
public class SecondArgMutablePlusOperation {
double[] apply(double[] arg1, double[] arg2) {
//sample mutation
arg2[0] = arg1[0] + arg2[0];
// still return arg2 as a result
return arg2;
}
}
public class ImmutablePlusOperation {
double[] apply(double[] arg1, double[] arg2) {
//sample mutation
double[] result = new double[arg1.length];
result[0] = arg1[0] + arg2[0];
return result;
}
}
Then a user can call apply method with correct strategy:
apply(arg1, arg2, new FirstArgMutablePlusOperation());
apply(arg1, arg2, new SecondArgMutablePlusOperation());
double[] result = apply(arg1, arg2, new ImmutablePlusOperation());
Immutable/mutable strategy can be a part of the BinaryOperation.
However, I rather avoid this solution as it will introduce if statements and a bulky implementation:
public enum ResultStrategy
{ RESULT, FIRST_ARG, SECOND_ARG };
public class PlusOperation extends BinaryOperation {
private final ResultStrategy strategy;
public PlusOperation(final ResultStrategy strategy) {
this.strategy = strategy
}
double[] apply(double[] arg1, double[] arg2) {
if(strategy == ResultStrategy.FIRST_ARG) {
//sample mutation
arg1[0] = arg1[0] + arg2[0];
// still return arg1 as a result
return arg1;
} else if(strategy == ResultStrategy.SECOND_ARG) {
//sample mutation
arg2[0] = arg1[0] + arg2[0];
// still return arg2 as a result
return arg2;
} else if(strategy == ResultStrategy.RESULT) {
double[] result = new double[arg1.length];
result[0] = arg1[0] + arg2[0];
return result;
}
}
}
Usage:
apply(arg1, arg2, new PlusOperation(ResultStrategy.FIRST_ARG));
apply(arg1, arg2, new PlusOperation(ResultStrategy.SECOND_ARG));
double[] result = apply(arg1, arg2, new PlusOperation(ResultStrategy.RESULT));
UPDATE
According to sample code provided in question
public enum ResultStrategy { FIRST_ARG, NEW_RESULT;} // SECOND_ARG = apply(b, a)
public class DoubleArraysMath {
...
public static double[] apply(ResultStrategy rs, double[] a, double[] b, BinaryOperation o) {
if (rs == ResultStrategy.FIRST_ARG) { return apply(a, a, b, o); }
return apply(new double[a.length], a, b, o);
}
}
I'm learning grails with json and I encountered this problem, which my JSON duplicate 4x in the same object and should be each, not all together:
[{"id":[2,1,4,3],"address":"[test.web.Address : 2, test.web.Address : 1, test.web.Address : 4, test.web.Address : 3]","range":[300,200,500,400],"placetype":"[Dangerous, Dangerous, Dangerous, Dangerous]"},{"id":[2,1,4,3],"address":"[test.web.Address : 2, test.web.Address : 1, test.web.Address : 4, test.web.Address : 3]","range":[300,200,500,400],"placetype":"[Dangerous, Dangerous, Dangerous, Dangerous]"},{"id":[2,1,4,3],"address":"[test.web.Address : 2, test.web.Address : 1, test.web.Address : 4, test.web.Address : 3]","range":[300,200,500,400],"placetype":"[Dangerous, Dangerous, Dangerous, Dangerous]"},{"id":[2,1,4,3],"address":"[test.web.Address : 2, test.web.Address : 1, test.web.Address : 4, test.web.Address : 3]","range":[300,200,500,400],"placetype":"[Dangerous, Dangerous, Dangerous, Dangerous]"}]
My domain Address:
Long id
String street
String city
Long zip;
int number
My domain Place:
Long id
Long range
PlaceType type
Address address
My Controller:
def avoid() {
def result = [];
def r = []
def a = Place.executeQuery("select distinct a from Place a where a.type = 1")
for (int i = 0; i < a.size(); i++) {
println(result)
result.add(a)
}
if (result) {
result.each() { place ->
r << [id: place.id,
address: place.address.street.toString(),
range: place.range,
placetype: place.type.toString()
];
}
} else {
println('error')
}
return jsonRender("JSON", params.callback, r)
}
PlaceType enum
enum PlaceType {
DANGEROUS('Dangerous', 1),
NOT_DANGEROUS('Not Dangerous', 2)
private final int id;
private final String description;
public PlaceType(String description, int id) {
this.description = description
this.id = id
}
public static PlaceType getById(int id) {
switch (id) {
case 1:
return DANGEROUS
case 2:
return NOT_DANGEROUS
}
}
#Override
public String toString() {
description
}
public short getId() {
id
}
}
Where I'm doing wrong? edit: test.web.Address now show the real address
there is a lot of "noise" in your groovy code...
I'd put it like that:
def avoid(){
render Place.findAllByType( PlaceType.Dangerous ).collect{ Place place ->
[id: place.id,
address: place.address.street.toString(),
range: place.range,
placetype: place.type.toString()
]
} as JSON
}
In this case you have a couple of possible error sources fewer.
Also I think, that stuff like place.type.toString() is wrong. The object shall be JSON-ified directly and the output should be a JSON-object rather that default toString() implementation
I don't know the method
jsonRender ("JSON", params.callback, r)
Please try this:
render r as JSON
and don't forget the import:
import grails.converters.*
see doc for render method: http://grails.org/doc/latest/ref/Controllers/render.html
or try to use the new response method: http://grails.org/doc/latest/ref/Controllers/respond.html
For my programming languages class, I am trying to understand how pass-by-name and pass-by-value-result work. I realize these aren't used hardly at all in mainstream languages, but I am wanting to get a feel for how they work. As an example (language agnostic):
void swap(int a, int b){
int t;
t = a;
a = b;
b = t;
}
void main() {
int val = 1, list[5] = {1, 2, 3, 4, 5}
swap(val, list[val]);
}
What would the values of val and list be after swap is called for both pass-by-value-result and pass-by-name.
An explanation would be great too.
From what I deduced, it got value-result: val=2, list={1,1,3,4,5} and name: val=3, list={1,2,1,4,5}. I'm very unsure about those results.
Also does it change the way both of these methods work when an array is passed as opposed to a single int? Thanks for any help in advance.
this code explain one of the problem of pass by name
this is why
in swap this is what happen
void swap(int a, int b){
int t;
t = a; //t=val; t=1
a = b;// val=list[val]; val=list[1]=2
b = t;// list[val]=t; list[2]=1
}
void main() {
int val = 1, list[5] = {1, 2, 3, 4, 5}
swap(val, list[val]);
}
as you can see the val changed at val=list[val] and it isn't the same val you passed anymore
as for pass by value result
void swap(int a=1, int b=2){
int t;
t = a; //a=1 so t=1
a = b; //b=2 so a=2
b = t; //b=1 so it and it return the right parameter so list[1]=2
}
i hope this helped
If you mean pass by name as pass by reference then the result will be the same as by value.
This is because you are only switching references between val and list position val. You are not passing an array reference.
Think of a var as a pointer to a block of memory that contains a value.